如何读取lucene索引数据

2025-04-30 22:40:48
推荐回答(1个)
回答1:

  我们一步一步来看。这里建设已经有实现建好索引,存放在index目录下。好,要读索引,总得先生成一个读索引器(即Lucene中IndexReader的实例)。好,写下面的程序(程序为C#程序,本文使用DotLucene)。
  IndexReader reader;
  问题出来了,IndexReader是一个abstract类,不能实例化。那好,换派生类试试看。找到IndexReader的两个孩子——SegmentReader和MultiReader。用哪个呢?无论是哪个都需要一大堆参数(我是颇费了周折才搞清楚它们的用途,后面再解释),似乎想用Lucene的索引数据不是那么容易啊。通过跟踪代码和查阅文档,我终于找到使用IndexReader的钥匙。原来IndexReader有一个“工厂模式”的static interface——IndexReader.Open。定义如下:
  #0001 public static IndexReader Open(System.String path)
  #0002 public static IndexReader Open(System.IO.FileInfo path)
  #0003 public static IndexReader Open(Directory directory)
  #0004 private static IndexReader Open(Directory directory, bool closeDirectory)
  其中有三个是public的接口,可供调用。打开一个索引,就是这么简单:
  #0001 IndexReader reader = IndexReader.Open(index);
  
  实际上,这个打开索引经历了这样的一个过程:
  #0001 SegmentInfos infos = new SegmentInfos();
  #0002 Directory directory = FSDirectory.GetDirectory(index, false);
  #0003 infos.Read(directory);
  #0004 bool closeDirectory = false;
  #0005 if (infos.Count == 1)
  #0006 {
  #0007 // index is optimized
  #0008 return new SegmentReader(infos, infos.Info(0), closeDirectory);
  #0009 }
  #0010 else
  #0011 {
  #0012 IndexReader[] readers = new IndexReader[infos.Count];
  #0013 for (int i = 0; i < infos.Count; i++)
  #0014 readers[i] = new SegmentReader(infos.Info(i));
  #0015 return new MultiReader(directory, infos, closeDirectory, readers);
  #0016 }
  
  首先要读入索引的段信息(segment information, #0001~#0003),然后看一下有几个段:如果只有一个,那么可能是优化过的,直接读取这一个段就可以(#0008);否则需要一次读入各个段(#0013~#0014),然后再拼成一个MultiReader(#0015)。打开索引文件的过程就是这样。
  

  接下来我们要看看如何读取信息了。用下面这段代码来说明。
  #0001 public static void PrintIndex(IndexReader reader)
  #0002 {
  #0003 //显示有多少个document
  #0004 System.Console.WriteLine(reader + "\tNumDocs = " + reader.NumDocs());
  #0005 for (int i = 0; i < reader.NumDocs(); i++)
  #0006 {
  #0007 System.Console.WriteLine(reader.Document(i));
  #0008 }
  #0009
  #0010 //枚举term,获得信息
  #0011 TermEnum termEnum = reader.Terms();
  #0012 while (termEnum.Next())
  #0013 {
  #0014 System.Console.Write(termEnum.Term());
  #0015 System.Console.WriteLine("\tDocFreq=" + termEnum.DocFreq());
  #0016
  #0017 TermPositions termPositions = reader.TermPositions(termEnum.Term());
  #0018 int i = 0;
  #0019 int j = 0;
  #0020 while (termPositions.Next())
  #0021 {
  #0022 System.Console.WriteLine((i++) + "->" + " DocNo:" + termPositions.Doc() + ", Freq:" + termPositions.Freq());
  #0023 for (j = 0; j < termPositions.Freq(); j++)
  #0024 System.Console.Write("[" + termPositions.NextPosition() + "]");
  #0025 System.Console.WriteLine();
  #0026 }
  #0027
  #0028 //直接获取 的信息
  #0029 TermDocs termDocs = reader.TermDocs(termEnum.Term());
  #0030 while (termDocs.Next())
  #0031 {
  #0032 System.Console.WriteLine((i++) + "->" + " DocNo:" + termDocs.Doc() + ", Freq:" + termDocs.Freq());
  #0033 }
  #0034 }
  #0035
  #0036 // FieldInfos fieldInfos = reader.fieldInfos;
  #0037 // FieldInfo pathFieldInfo = fieldInfos.FieldInfo("path");
  #0038
  #0039 //显示 term frequency vector
  #0040 for (int i = 0; i < reader.NumDocs(); i++)
  #0041 {
  #0042 //对contents的token之后的term存于了TermFreqVector
  #0043 TermFreqVector termFreqVector = reader.GetTermFreqVector(i, "contents");
  #0044
  #0045 if (termFreqVector == null)
  #0046 {
  #0047 System.Console.WriteLine("termFreqVector is null.");
  #0048 continue;
  #0049 }
  #0050
  #0051 String fieldName = termFreqVector.GetField();
  #0052 String[] terms = termFreqVector.GetTerms();
  #0053 int[] frequences = termFreqVector.GetTermFrequencies();
  #0054
  #0055 System.Console.Write("FieldName:" + fieldName);
  #0056 for (int j = 0; j < terms.Length; j++)
  #0057 {
  #0058 System.Console.Write("[" + terms[j] + ":" + frequences[j] + "]");
  #0059 }
  #0060 System.Console.WriteLine();
  #0061 }
  #0062 System.Console.WriteLine();
  #0063 }
  
  #0004 计算document的个数
  #0012~#0034 枚举collection中所有的term
  其中#0017~#0026 枚举每个term在出现的document中的所有位置(第几个词,从1开始计数);#0029~#0033 计算每个term出现在哪些文档和相应的出现频度(即DF和TF)。
  #0036~#0037在reader是SegmentReader类型的情况下有效。
  #0040~#0061可以快速的读取某篇文档中出现的term和相应的频度。但是这部分需要在建索引时,设置storeTermVector为true。比如
  doc.Add(Field.Text("contents", reader, true));
  其中的第三项即是。默认为false。
  

  有了这些数据,就可以统计我需要的数据了。以后我会介绍如何建立索引,如何应用Lucene。