SegmentMerger.cs
上传用户:zhangkuixh
上传日期:2013-09-30
资源大小:5473k
文件大小:14k
源码类别:

搜索引擎

开发平台:

C#

  1. /*
  2.  * Copyright 2004 The Apache Software Foundation
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  * 
  8.  * http://www.apache.org/licenses/LICENSE-2.0
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16. using System;
  17. using Directory = Lucene.Net.Store.Directory;
  18. using IndexOutput = Lucene.Net.Store.IndexOutput;
  19. using RAMOutputStream = Lucene.Net.Store.RAMOutputStream;
  20. namespace Lucene.Net.Index
  21. {
  22. /// <summary> The SegmentMerger class combines two or more Segments, represented by an IndexReader ({@link #add},
  23. /// into a single Segment.  After adding the appropriate readers, call the merge method to combine the 
  24. /// segments.
  25. /// <P> 
  26. /// If the compoundFile flag is set, then the segments will be merged into a compound file.
  27. /// 
  28. /// 
  29. /// </summary>
  30. /// <seealso cref="merge">
  31. /// </seealso>
  32. /// <seealso cref="add">
  33. /// </seealso>
  34. public sealed class SegmentMerger
  35. {
  36. private void  InitBlock()
  37. {
  38. termIndexInterval = IndexWriter.DEFAULT_TERM_INDEX_INTERVAL;
  39. }
  40. private Directory directory;
  41. private System.String segment;
  42. private int termIndexInterval;
  43. private System.Collections.ArrayList readers = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  44. private FieldInfos fieldInfos;
  45. /// <summary>This ctor used only by test code.
  46. /// 
  47. /// </summary>
  48. /// <param name="dir">The Directory to merge the other segments into
  49. /// </param>
  50. /// <param name="name">The name of the new segment
  51. /// </param>
  52. public /*internal*/ SegmentMerger(Directory dir, System.String name)
  53. {
  54. InitBlock();
  55. directory = dir;
  56. segment = name;
  57. }
  58. internal SegmentMerger(IndexWriter writer, System.String name)
  59. {
  60. InitBlock();
  61. directory = writer.GetDirectory();
  62. segment = name;
  63. termIndexInterval = writer.GetTermIndexInterval();
  64. }
  65. /// <summary> Add an IndexReader to the collection of readers that are to be merged</summary>
  66. /// <param name="reader">
  67. /// </param>
  68. public /*internal*/ void  Add(IndexReader reader)
  69. {
  70. readers.Add(reader);
  71. }
  72. /// <summary> </summary>
  73. /// <param name="i">The index of the reader to return
  74. /// </param>
  75. /// <returns> The ith reader to be merged
  76. /// </returns>
  77. internal IndexReader SegmentReader(int i)
  78. {
  79. return (IndexReader) readers[i];
  80. }
  81. /// <summary> Merges the readers specified by the {@link #add} method into the directory passed to the constructor</summary>
  82. /// <returns> The number of documents that were merged
  83. /// </returns>
  84. /// <throws>  IOException </throws>
  85. public /*internal*/ int Merge()
  86. {
  87. int value_Renamed;
  88. value_Renamed = MergeFields();
  89. MergeTerms();
  90. MergeNorms();
  91. if (fieldInfos.HasVectors())
  92. MergeVectors();
  93. return value_Renamed;
  94. }
  95. /// <summary> close all IndexReaders that have been added.
  96. /// Should not be called before merge().
  97. /// </summary>
  98. /// <throws>  IOException </throws>
  99. public /*internal*/ void  CloseReaders()
  100. {
  101. for (int i = 0; i < readers.Count; i++)
  102. {
  103. // close readers
  104. IndexReader reader = (IndexReader) readers[i];
  105. reader.Close();
  106. }
  107. }
  108. internal System.Collections.ArrayList CreateCompoundFile(System.String fileName)
  109. {
  110. CompoundFileWriter cfsWriter = new CompoundFileWriter(directory, fileName);
  111. System.Collections.ArrayList files = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(IndexFileNames.COMPOUND_EXTENSIONS.Length + fieldInfos.Size()));
  112. // Basic files
  113. for (int i = 0; i < IndexFileNames.COMPOUND_EXTENSIONS.Length; i++)
  114. {
  115. files.Add(segment + "." + IndexFileNames.COMPOUND_EXTENSIONS[i]);
  116. }
  117. // Field norm files
  118. for (int i = 0; i < fieldInfos.Size(); i++)
  119. {
  120. FieldInfo fi = fieldInfos.FieldInfo(i);
  121. if (fi.isIndexed && !fi.omitNorms)
  122. {
  123. files.Add(segment + ".f" + i);
  124. }
  125. }
  126. // Vector files
  127. if (fieldInfos.HasVectors())
  128. {
  129. for (int i = 0; i < IndexFileNames.VECTOR_EXTENSIONS.Length; i++)
  130. {
  131. files.Add(segment + "." + IndexFileNames.VECTOR_EXTENSIONS[i]);
  132. }
  133. }
  134. // Now merge all added files
  135. System.Collections.IEnumerator it = files.GetEnumerator();
  136. while (it.MoveNext())
  137. {
  138. cfsWriter.AddFile((System.String) it.Current);
  139. }
  140. // Perform the merge
  141. cfsWriter.Close();
  142. return files;
  143. }
  144. private void  AddIndexed(IndexReader reader, FieldInfos fieldInfos, System.Collections.ICollection names, bool storeTermVectors, bool storePositionWithTermVector, bool storeOffsetWithTermVector)
  145. {
  146. System.Collections.IEnumerator i = names.GetEnumerator();
  147. while (i.MoveNext())
  148. {
  149.                 System.Collections.DictionaryEntry e = (System.Collections.DictionaryEntry) i.Current;
  150.                 System.String field = (System.String) e.Key;
  151. fieldInfos.Add(field, true, storeTermVectors, storePositionWithTermVector, storeOffsetWithTermVector, !reader.HasNorms(field));
  152. }
  153. }
  154. /// <summary> </summary>
  155. /// <returns> The number of documents in all of the readers
  156. /// </returns>
  157. /// <throws>  IOException </throws>
  158. private int MergeFields()
  159. {
  160. fieldInfos = new FieldInfos(); // merge field names
  161. int docCount = 0;
  162. for (int i = 0; i < readers.Count; i++)
  163. {
  164. IndexReader reader = (IndexReader) readers[i];
  165. AddIndexed(reader, fieldInfos, reader.GetFieldNames(IndexReader.FieldOption.TERMVECTOR_WITH_POSITION_OFFSET), true, true, true);
  166. AddIndexed(reader, fieldInfos, reader.GetFieldNames(IndexReader.FieldOption.TERMVECTOR_WITH_POSITION), true, true, false);
  167. AddIndexed(reader, fieldInfos, reader.GetFieldNames(IndexReader.FieldOption.TERMVECTOR_WITH_OFFSET), true, false, true);
  168. AddIndexed(reader, fieldInfos, reader.GetFieldNames(IndexReader.FieldOption.TERMVECTOR), true, false, false);
  169. AddIndexed(reader, fieldInfos, reader.GetFieldNames(IndexReader.FieldOption.INDEXED), false, false, false);
  170. fieldInfos.Add(reader.GetFieldNames(IndexReader.FieldOption.UNINDEXED), false);
  171. }
  172. fieldInfos.Write(directory, segment + ".fnm");
  173. FieldsWriter fieldsWriter = new FieldsWriter(directory, segment, fieldInfos);
  174. try
  175. {
  176. for (int i = 0; i < readers.Count; i++)
  177. {
  178. IndexReader reader = (IndexReader) readers[i];
  179. int maxDoc = reader.MaxDoc();
  180. for (int j = 0; j < maxDoc; j++)
  181. if (!reader.IsDeleted(j))
  182. {
  183. // skip deleted docs
  184. fieldsWriter.AddDocument(reader.Document(j));
  185. docCount++;
  186. }
  187. }
  188. }
  189. finally
  190. {
  191. fieldsWriter.Close();
  192. }
  193. return docCount;
  194. }
  195. /// <summary> Merge the TermVectors from each of the segments into the new one.</summary>
  196. /// <throws>  IOException </throws>
  197. private void  MergeVectors()
  198. {
  199. TermVectorsWriter termVectorsWriter = new TermVectorsWriter(directory, segment, fieldInfos);
  200. try
  201. {
  202. for (int r = 0; r < readers.Count; r++)
  203. {
  204. IndexReader reader = (IndexReader) readers[r];
  205. int maxDoc = reader.MaxDoc();
  206. for (int docNum = 0; docNum < maxDoc; docNum++)
  207. {
  208. // skip deleted docs
  209. if (reader.IsDeleted(docNum))
  210. continue;
  211. termVectorsWriter.AddAllDocVectors(reader.GetTermFreqVectors(docNum));
  212. }
  213. }
  214. }
  215. finally
  216. {
  217. termVectorsWriter.Close();
  218. }
  219. }
  220. private IndexOutput freqOutput = null;
  221. private IndexOutput proxOutput = null;
  222. private TermInfosWriter termInfosWriter = null;
  223. private int skipInterval;
  224. private SegmentMergeQueue queue = null;
  225. private void  MergeTerms()
  226. {
  227. try
  228. {
  229. freqOutput = directory.CreateOutput(segment + ".frq");
  230. proxOutput = directory.CreateOutput(segment + ".prx");
  231. termInfosWriter = new TermInfosWriter(directory, segment, fieldInfos, termIndexInterval);
  232. skipInterval = termInfosWriter.skipInterval;
  233. queue = new SegmentMergeQueue(readers.Count);
  234. MergeTermInfos();
  235. }
  236. finally
  237. {
  238. if (freqOutput != null)
  239. freqOutput.Close();
  240. if (proxOutput != null)
  241. proxOutput.Close();
  242. if (termInfosWriter != null)
  243. termInfosWriter.Close();
  244. if (queue != null)
  245. queue.Close();
  246. }
  247. }
  248. private void  MergeTermInfos()
  249. {
  250. int base_Renamed = 0;
  251. for (int i = 0; i < readers.Count; i++)
  252. {
  253. IndexReader reader = (IndexReader) readers[i];
  254. TermEnum termEnum = reader.Terms();
  255. SegmentMergeInfo smi = new SegmentMergeInfo(base_Renamed, termEnum, reader);
  256. base_Renamed += reader.NumDocs();
  257. if (smi.Next())
  258. queue.Put(smi);
  259. // initialize queue
  260. else
  261. smi.Close();
  262. }
  263. SegmentMergeInfo[] match = new SegmentMergeInfo[readers.Count];
  264. while (queue.Size() > 0)
  265. {
  266. int matchSize = 0; // pop matching terms
  267. match[matchSize++] = (SegmentMergeInfo) queue.Pop();
  268. Term term = match[0].term;
  269. SegmentMergeInfo top = (SegmentMergeInfo) queue.Top();
  270. while (top != null && term.CompareTo(top.term) == 0)
  271. {
  272. match[matchSize++] = (SegmentMergeInfo) queue.Pop();
  273. top = (SegmentMergeInfo) queue.Top();
  274. }
  275. MergeTermInfo(match, matchSize); // add new TermInfo
  276. while (matchSize > 0)
  277. {
  278. SegmentMergeInfo smi = match[--matchSize];
  279. if (smi.Next())
  280. queue.Put(smi);
  281. // restore queue
  282. else
  283. smi.Close(); // done with a segment
  284. }
  285. }
  286. }
  287. private TermInfo termInfo = new TermInfo(); // minimize consing
  288. /// <summary>Merge one term found in one or more segments. The array <code>smis</code>
  289. /// contains segments that are positioned at the same term. <code>N</code>
  290. /// is the number of cells in the array actually occupied.
  291. /// 
  292. /// </summary>
  293. /// <param name="smis">array of segments
  294. /// </param>
  295. /// <param name="n">number of cells in the array actually occupied
  296. /// </param>
  297. private void  MergeTermInfo(SegmentMergeInfo[] smis, int n)
  298. {
  299. long freqPointer = freqOutput.GetFilePointer();
  300. long proxPointer = proxOutput.GetFilePointer();
  301. int df = AppendPostings(smis, n); // append posting data
  302. long skipPointer = WriteSkip();
  303. if (df > 0)
  304. {
  305. // add an entry to the dictionary with pointers to prox and freq files
  306. termInfo.Set(df, freqPointer, proxPointer, (int) (skipPointer - freqPointer));
  307. termInfosWriter.Add(smis[0].term, termInfo);
  308. }
  309. }
  310. /// <summary>Process postings from multiple segments all positioned on the
  311. /// same term. Writes out merged entries into freqOutput and
  312. /// the proxOutput streams.
  313. /// 
  314. /// </summary>
  315. /// <param name="smis">array of segments
  316. /// </param>
  317. /// <param name="n">number of cells in the array actually occupied
  318. /// </param>
  319. /// <returns> number of documents across all segments where this term was found
  320. /// </returns>
  321. private int AppendPostings(SegmentMergeInfo[] smis, int n)
  322. {
  323. int lastDoc = 0;
  324. int df = 0; // number of docs w/ term
  325. ResetSkip();
  326. for (int i = 0; i < n; i++)
  327. {
  328. SegmentMergeInfo smi = smis[i];
  329. TermPositions postings = smi.GetPositions();
  330. int base_Renamed = smi.base_Renamed;
  331. int[] docMap = smi.GetDocMap();
  332. postings.Seek(smi.termEnum);
  333. while (postings.Next())
  334. {
  335. int doc = postings.Doc();
  336. if (docMap != null)
  337. doc = docMap[doc]; // map around deletions
  338. doc += base_Renamed; // convert to merged space
  339. if (doc < lastDoc)
  340. throw new System.SystemException("docs out of order");
  341. df++;
  342. if ((df % skipInterval) == 0)
  343. {
  344. BufferSkip(lastDoc);
  345. }
  346. int docCode = (doc - lastDoc) << 1; // use low bit to flag freq=1
  347. lastDoc = doc;
  348. int freq = postings.Freq();
  349. if (freq == 1)
  350. {
  351. freqOutput.WriteVInt(docCode | 1); // write doc & freq=1
  352. }
  353. else
  354. {
  355. freqOutput.WriteVInt(docCode); // write doc
  356. freqOutput.WriteVInt(freq); // write frequency in doc
  357. }
  358. int lastPosition = 0; // write position deltas
  359. for (int j = 0; j < freq; j++)
  360. {
  361. int position = postings.NextPosition();
  362. proxOutput.WriteVInt(position - lastPosition);
  363. lastPosition = position;
  364. }
  365. }
  366. }
  367. return df;
  368. }
  369. private RAMOutputStream skipBuffer = new RAMOutputStream();
  370. private int lastSkipDoc;
  371. private long lastSkipFreqPointer;
  372. private long lastSkipProxPointer;
  373. private void  ResetSkip()
  374. {
  375. skipBuffer.Reset();
  376. lastSkipDoc = 0;
  377. lastSkipFreqPointer = freqOutput.GetFilePointer();
  378. lastSkipProxPointer = proxOutput.GetFilePointer();
  379. }
  380. private void  BufferSkip(int doc)
  381. {
  382. long freqPointer = freqOutput.GetFilePointer();
  383. long proxPointer = proxOutput.GetFilePointer();
  384. skipBuffer.WriteVInt(doc - lastSkipDoc);
  385. skipBuffer.WriteVInt((int) (freqPointer - lastSkipFreqPointer));
  386. skipBuffer.WriteVInt((int) (proxPointer - lastSkipProxPointer));
  387. lastSkipDoc = doc;
  388. lastSkipFreqPointer = freqPointer;
  389. lastSkipProxPointer = proxPointer;
  390. }
  391. private long WriteSkip()
  392. {
  393. long skipPointer = freqOutput.GetFilePointer();
  394. skipBuffer.WriteTo(freqOutput);
  395. return skipPointer;
  396. }
  397. private void  MergeNorms()
  398. {
  399. for (int i = 0; i < fieldInfos.Size(); i++)
  400. {
  401. FieldInfo fi = fieldInfos.FieldInfo(i);
  402. if (fi.isIndexed && !fi.omitNorms)
  403. {
  404. IndexOutput output = directory.CreateOutput(segment + ".f" + i);
  405. try
  406. {
  407. for (int j = 0; j < readers.Count; j++)
  408. {
  409. IndexReader reader = (IndexReader) readers[j];
  410. int maxDoc = reader.MaxDoc();
  411. byte[] input = new byte[maxDoc];
  412. reader.Norms(fi.name, input, 0);
  413. for (int k = 0; k < maxDoc; k++)
  414. {
  415. if (!reader.IsDeleted(k))
  416. {
  417. output.WriteByte(input[k]);
  418. }
  419. }
  420. }
  421. }
  422. finally
  423. {
  424. output.Close();
  425. }
  426. }
  427. }
  428. }
  429. }
  430. }