我是Lucene的新手,我在创建简单的代码以查询文本文件集时遇到了一些问题。
我尝试了this example,但与新版本的Lucene不兼容。
UDPATE: This is my new code,但它仍然无效。
答案 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();
搜索有点棘手。您需要多个类:Query
和QueryParser
来从字符串中进行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