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

时间:2010-11-03 20:36:42

标签: java indexing lucene text-files

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

我尝试了this example,但与新版本的Lucene不兼容。

UDPATE: This is my new code,但它仍然无效。

3 个答案:

答案 0 :(得分:33)

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构造函数采用字段名称,文本和至少 2个参数。首先是一个标志,显示Lucene是否必须存储此字段。如果它等于Field.Store.YES,您将有可能从索引中获取所有文本,否则只会存储有关它的索引信息。
第二个参数显示Lucene是否必须索引此字段。对要搜索的任何字段使用Field.Index.ANALYZED 通常,您使用上述两个参数。

完成工作后别忘了关闭IndexWriter

writer.close();

搜索有点棘手。您需要多个类:QueryQueryParser来从字符串中进行Lucene查询,IndexSearcher进行实际搜索,TopScoreDocCollector来存储结果(将其传递给{{1} }}作为参数)和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(); } 构造函数的第二个参数 - 它是默认字段,即如果没有给出限定符则将搜索的字段。例如,如果您的查询是“title:term”,Lucene将在所有文档的字段“title”中搜索单词“term”,但如果您的查询只是“term”,则会在默认字段中搜索,在这种情况下 - “内容”。有关详细信息,请参阅Lucene Query Syntax QueryParser也将分析器作为最后一个参数。这必须与您用于索引文本的分析器相同。

您必须知道的最后一件事是QueryParser第一个参数。它只是一个数字,表示您要收集的结果数量。例如,如果它等于100,Lucene将仅收集第一个(按分数)100个结果并删除其余部分。这只是一种优化行为 - 您收集最佳结果,如果您对此不满意,则重复搜索更大的数字。

最后,不要忘记关闭搜索器和目录,以免丢失系统资源:

TopScoreDocCollector.create

编辑:另请参阅IndexFiles demo class中的Lucene 3.0 sources

答案 1 :(得分: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();

 }

}

答案 2 :(得分:1)

我建议你研究Solr @ http://lucene.apache.org/solr/,而不是使用lucene api