如何在Lucene 3.0.2中索引和搜索文本文件?

11

我是Lucene的新手,我在创建简单代码来查询文本文件集合方面遇到了一些问题。

我尝试过这个例子,但它与新版本的Lucene不兼容。

更新:这是我的新代码,但它还没有生效。

3个回答

35

Lucene是一个涉及大量类和方法的话题,如果你不了解至少一些基本概念,通常无法使用它。如果你需要快速可用的服务,请使用Solr。如果你需要完全控制Lucene,请继续阅读。我将介绍一些代表核心Lucene概念和类的内容(有关如何在内存中读取文本文件的信息,请参阅 this 文章)。

无论你想要在Lucene中做什么-建立索引还是搜索-你都需要一个分析器。分析器的目标是将输入文本进行标记化(拆分成单词)和词干提取(获取单词的基础形式)。它还会去除最常见的词,例如"a"、"the"等。你可以找到适用于20多种语言的分析器,或者使用SnowballAnalyzer并将语言作为参数传递。
为了创建SnowballAnalyzer的英文实例,你可以这样做:

Analyzer analyzer = new SnowballAnalyzer(Version.LUCENE_30, "English");

如果你要索引不同语言的文本,并希望自动选择分析器,则可以使用tika's LanguageIdentifier
你需要将索引存储在某个地方。这有两个主要可能性:内存索引,这很容易尝试,和磁盘索引,这是最广泛使用的一种。
使用下面的任意一行:
Directory directory = new RAMDirectory();   // RAM index storage
Directory directory = FSDirectory.open(new File("/path/to/index"));  // disk index storage

当您想要添加、更新或删除文档时,需要使用IndexWriter:
IndexWriter writer = new IndexWriter(directory, analyzer, true, new IndexWriter.MaxFieldLength(25000));

任何文档(在您的情况下为文本文件)都是一组字段。要创建用于保存有关文件信息的文档,请使用以下内容:

Document doc = new Document();
String title = nameOfYourFile;
doc.add(new Field("title", title, Field.Store.YES, Field.Index.ANALYZED));  // adding title field
String content = contentsOfYourFile;
doc.add(new Field("content", content, Field.Store.YES, Field.Index.ANALYZED)); // adding content field
writer.addDocument(doc);  // writing new document to the index

Field构造函数需要字段名称、文本以及至少两个参数。第一个是标志,用于指示Lucene是否必须存储此字段。如果它等于Field.Store.YES,则您将有可能从索引中获取所有文本,否则只有关于其的索引信息将被存储。
第二个参数显示Lucene是否必须对此字段进行索引。对于任何要搜索的字段,请使用Field.Index.ANALYZED
通常,您可以像上面显示的那样同时使用这两个参数。

在完成工作后不要忘记关闭您的IndexWriter

writer.close();

搜索有些棘手。您需要几个类:QueryQueryParser从字符串创建Lucene查询,IndexSearcher用于实际搜索,TopScoreDocCollector存储结果(作为参数传递给IndexSearcher),以及ScoreDoc迭代结果。下面的代码片段显示了所有内容的组合:

IndexSearcher searcher = new IndexSearcher(directory);
QueryParser parser = new QueryParser(Version.LUCENE_30, "content", analyzer);
Query query = parser.parse("terms to search");
TopScoreDocCollector collector = TopScoreDocCollector.create(HOW_MANY_RESULTS_TO_COLLECT, true);
searcher.search(query, collector);

ScoreDoc[] hits = collector.topDocs().scoreDocs;
// `i` is just a number of document in Lucene. Note, that this number may change after document deletion 
for (int i = 0; i < hits.length; i++) {
    Document hitDoc = searcher.doc(hits[i].doc);  // getting actual document
    System.out.println("Title: " + hitDoc.get("title"));
    System.out.println("Content: " + hitDoc.get("content"));
    System.out.println();
}

注意QueryParser构造函数的第二个参数 - 它是默认字段,即如果没有限定符,则将搜索该字段。例如,如果您的查询是"title:term",则Lucene将在所有文档的"title"字段中搜索单词"term",但如果您的查询只是"term",则将在默认字段中搜索,在本例中为"contents"。有关更多信息,请参见Lucene查询语法
QueryParser还需要分析器作为最后一个参数。这必须是与用于索引文本的分析器相同的分析器。
你必须知道的最后一件事是TopScoreDocCollector.create的第一个参数。它只是一个数字,表示要收集多少结果。例如,如果它等于100,则Lucene仅会收集前100个(按分数排序)的结果并丢弃其余的结果。这只是优化的行为 - 您收集最佳结果,如果不满意,则可以使用更大的数字重复搜索。
最后,不要忘记关闭搜索器和目录,以免浪费系统资源:
searcher.close();
directory.close();

编辑:另请参见Lucene 3.0源代码中的IndexFiles演示类


在第80行中,你有:QueryParser parser = new QueryParser(Version.LUCENE_30, "computer", analyzer);,即你将第二个参数(默认字段)设置为"computer",然后在没有限定符的情况下进行搜索。Lucene 尝试使用默认字段"computer"来查找术语"computer",由于你的文档没有这样的字段,所以 Lucene 失败了。使用 QueryParser parser = new QueryParser(Version.LUCENE_30, "content", analyzer); 或者带限定符的搜索:Query query = parser.parse("content:computer"); - ffriend

3
package org.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;


import org.apache.lucene.queryParser.*;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;

public class LuceneSimple {

 private static void addDoc(IndexWriter w, String value) throws IOException {
  Document doc = new Document();
  doc.add(new Field("title", value, Field.Store.YES, Field.Index.ANALYZED));
  w.addDocument(doc);
 }



 public static void main(String[] args) throws CorruptIndexException, LockObtainFailedException, IOException, ParseException {

     File dir = new File("F:/tmp/dir");

  StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);

  Directory index = new RAMDirectory();
  //Directory index = FSDirectory.open(new File("lucDirHello") );


  IndexWriter w = new IndexWriter(index, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);

  w.setRAMBufferSizeMB(200);

  System.out.println(index.getClass() + " RamBuff:" + w.getRAMBufferSizeMB() );

  addDoc(w, "Lucene in Action");
     addDoc(w, "Lucene for Dummies");
     addDoc(w, "Managing Gigabytes");
     addDoc(w, "The Art of Computer Science");
     addDoc(w, "Computer Science ! what is that ?");


     Long N = 0l;

     for( File f : dir.listFiles() ){
      BufferedReader br = new BufferedReader( new FileReader(f) );
      String line = null;
      while( ( line = br.readLine() ) != null ){
       if( line.length() < 140 ) continue;      
       addDoc(w, line);
       ++N;
      }
      br.close();
     }

     w.close();

     // 2. query
     String querystr = "Computer";

     Query q = new QueryParser( Version.LUCENE_30, "title", analyzer ).parse(querystr);


     //search
     int hitsPerPage = 10;

     IndexSearcher searcher = new IndexSearcher(index, true);

     TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, true);

     searcher.search(q, collector);

     ScoreDoc[] hits = collector.topDocs().scoreDocs;

     System.out.println("Found " + hits.length + " hits.");
     for(int i=0;i<hits.length;++i) {
       int docId = hits[i].doc;
       Document d = searcher.doc(docId);
       System.out.println((i + 1) + ". " + d.get("title"));
     }


     searcher.close();

 }

}

你可以将“File dir”变量设置为你需要索引的目录。 - smartnut007

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接