Lucene 初级教程


Lucene 初级教程 2007-12-26 15:24 点击次数:0 次 1 lucene 简介 1.1 什么是 lucene Lucene 是一个全文搜索框架,而不是应用产品。因此它并不像 www.baidu.com 或者 go ogle Desktop 那么拿来就能用,它只是提供了一种工具让你能实现这些产品。 2 lucene 的工作方式 lucene 提供的服务实际包含两部分:一入一出。所谓入是写入,即将你提供的源(本 质是字符串)写入索引或者将其从索引中删除;所谓出是读出,即向用户提供全文搜索服务, 让用户可以通过关键词定位源。 2.1 写入流程 源字符串首先经过 analyzer 处理,包括:分词,分成一个个单词;去除 stopword(可 选)。 将源中需要的信息加入 Document 的各个 Field 中,并把需要索引的 Field 索引起来,把需 要存储的 Field 存储起来。 将索引写入存储器,存储器可以是内存或磁盘。 2.2 读出流程 用户提供搜索关键词,经过 analyzer 处理。 对处理后的关键词搜索索引找出对应的 Document。 用户根据需要从找到的 Document 中提取需要的 Field。 3 一些需要知道的概念 3.1 analyzer Analyzer 是分析器,它的作用是把一个字符串按某种规则划分成一个个词语,并去除 其中的无效词语,这里说的无效词语是指英文中的“of”、“the”,中文中的“的”、“地” 等词语,这些词语在文章中大量出现,但是本身不包含什么关键信息,去掉有利于缩小索引 文件、提高效率、提高命中率。 分词的规则千变万化,但目的只有一个:按语义划分。这点在英文中比较容易实现,因 为英文本身就是以单词为单位的,已经用空格分开;而中文则必须以某种方法将连成一片的 句子划分成一个个词语。具体划分方法下面再详细介绍,这里只需了解分析器的概念即可。 3.2 document 用户提供的源是一条条记录,它们可以是文本文件、字符串或者数据库表的一条记录等 等。一条记录经过索引之后,就是以一个 Document 的形式存储在索引文件中的。用户进行 搜索,也是以 Document 列表的形式返回。 3.3 field 一个 Document 可以包含多个信息域,例如一篇文章可以包含“标题”、“正文”、“最 后修改时间”等信息域,这些信息域就是通过 Field 在 Document 中存储的。 Field 有两个属性可选:存储和索引。通过存储属性你可以控制是否对这个 Field 进行 存储;通过索引属性你可以控制是否对该 Field 进行索引。这看起来似乎有些废话,事实上 对这两个属性的正确组合很重要,下面举例说明:还是以刚才的文章为例子,我们需要对标 题和正文进行全文搜索,所以我们要把索引属性设置为真,同时我们希望能直接从搜索结果 中提取文章标题,所以我们把标题域的存储属性设置为真,但是由于正文域太大了,我们为 了缩小索引文件大小,将正文域的存储属性设置为假,当需要时再直接读取文件;我们只是 希望能从搜索解果中提取最后修改时间,不需要对它进行搜索,所以我们把最后修改时间域 的存储属性设置为真,索引属性设置为假。上面的三个域涵盖了两个属性的三种组合,还有 一种全为假的没有用到,事实上 Field 不允许你那么设置,因为既不存储又不索引的域是没 有意义的。 3.4 term term 是搜索的最小单位,它表示文档的一个词语,term 由两部分组成:它表示的词语 和这个词语所出现的 field。 3.5 tocken tocken 是 term 的一次出现,它包含 trem 文本和相应的起止偏移,以及一个类型字符 串。一句话中可以出现多次相同的词语,它们都用同一个 term 表示,但是用不同的 tocken, 每个 tocken 标记该词语出现的地方。 3.6 segment 添加索引时并不是每个 document 都马上添加到同一个索引文件,它们首先被写入到不 同的小文件,然后再合并成一个大索引文件,这里每个小文件都是一个 segment。 4 如何建索引 4.1 最简单的能完成索引的代码片断 IndexWriter writer = new IndexWriter(“/data/index/”, new StandardAnalyzer(), true); Document doc = new Document(); doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index. TOKENIZED)); doc.add(new Field("content", "lucene works well", Field.Store.YES, Field.Index. TOKENIZED)); writer.addDocument(doc); writer.optimize(); writer.close(); 下面我们分析一下这段代码。 首先我们创建了一个 writer,并指定存放索引的目录为“/data/index”,使用的分析器为 StandardAnalyzer,第三个参数说明如果已经有索引文件在索引目录下,我们将覆盖它们。 然后我们新建一个 document。 我们向 document 添加一个 field,名字是“title”,内容是“lucene introduction”, 对它进行存储并索引。再添加一个名字是“content”的 field,内容是“lucene works we ll”,也是存储并索引。 然后我们将这个文档添加到索引中,如果有多个文档,可以重复上面的操作,创建 documen t 并添加。 添加完所有 document,我们对索引进行优化,优化主要是将多个 segment 合并到一个,有 利于提高索引速度。 随后将 writer 关闭,这点很重要。 对,创建索引就这么简单! 当然你可能修改上面的代码获得更具个性化的服务。 4.2 索引文本文件 如果你想把纯文本文件索引起来,而不想自己将它们读入字符串创建 field,你可以用 下面的代码创建 field: Field field = new Field("content", new FileReader(file)); 这里的 file 就是该文本文件。该构造函数实际上是读去文件内容,并对其进行索引, 但不存储。 Lucene 2 教程 Lucene 是 apache 组织的一个用 java 实现全文搜索引擎的开源项目。 其功能 非常的强大,api 也很简单。总得来说用 Lucene 来进行建立 和搜索和操作数据 库是差不多的(有点像),Document 可以看作是 数据库的一行记录,Field 可以 看作是数据库的字段。用 lucene 实 现搜索引擎就像用 JDBC 实现连接数据库一 样简单。 Lucene2.0,它与以前广泛应用和介绍的 Lucene 1.4.3 并不兼容。 Lucene2.0 的下载地址是 http://apache.justdn.org/lucene/java/ 例子一 : 1、在 windows 系统下的的 C 盘,建一个名叫 s 的文件夹,在该文件夹里面随便 建三个 txt 文件,随便起名啦,就叫"1.txt","2.txt"和"3.txt"啦 其中 1.txt 的内容如下: 中华人民共和国 全国人民 2006 年 而"2.txt"和"3.txt"的内容也可以随便写几写,这里懒写,就复制一个和 1.txt 文件的内容一样吧 2、下载 lucene 包,放在 classpath 路径中 建立索引: package lighter.javaeye.com; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; /** * author lighter date 2006-8-7 */ public class TextFileIndexer { public static void main(String[] args) throws Exception { /* 指明要索引文件夹的位置,这里是 C 盘的 S 文件夹下 */ File fileDir = new File( " c:\\s " ); /* 这里放索引文件的位置 */ File indexDir = new File( " c:\\index " ); Analyzer luceneAnalyzer = new StandardAnalyzer(); IndexWriter indexWriter = new IndexWriter(indexDir, luceneAnalyze r, true ); File[] textFiles = fileDir.listFiles(); long startTime = new Date().getTime(); // 增加 document 到索引去 for ( int i = 0 ; i < textFiles.length; i ++ ) { if (textFiles[i].isFile() && textFiles[i].getName().endsWith( " .txt " )) { System.out.println( " File " + textFiles[i].getCanonicalPath() + " 正在被索引 . " ); String temp = FileReaderAll(textFiles[i].getCanonicalPath(), " GBK " ); System.out.println(temp); Document document = new Document(); Field FieldPath = new Field( " path " , textFiles[i].getPath(), Field.Store.YES, Field.Index.NO); Field FieldBody = new Field( " body " , temp, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.WITH_POSITIONS_OFFSETS); document.add(FieldPath); document.add(FieldBody); indexWriter.addDocument(document); } } // optimize()方法是对索引进行优化 indexWriter.optimize(); indexWriter.close(); // 测试一下索引的时间 long endTime = new Date().getTime(); System.out .println( " 这花费了 " + (endTime - startTime) + " 毫秒来把文档增加到索引里面去! " + fileDir.getPath()); } public static String FileReaderAll(String FileName, String charset) throws IOException { BufferedReader reader = new BufferedReader( new InputStreamRead er( new FileInputStream(FileName), charset)); String line = new String(); String temp = new String(); while ((line = reader.readLine()) != null ) { temp += line; } reader.close(); return temp; } } 索引的结果: File C:\s\ 1 .txt 正在被索引 . 中华人民共和国全国人民 2006 年 File C:\s\ 2 .txt 正在被索引 . 中华人民共和国全国人民 2006 年 File C:\s\ 3 .txt 正在被索引 . 中华人民共和国全国人民 2006 年 这花费了 297 毫秒来把文档增加到索引里面去 ! c:\s 3、建立了索引之后,查询啦.... package lighter.javaeye.com; import java.io.IOException; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; public class TestQuery { public static void main(String[] args) throws IOException, ParseExc eption { Hits hits = null ; String queryString = " 中华 " ; Query query = null ; IndexSearcher searcher = new IndexSearcher( " c:\\index " ); Analyzer analyzer = new StandardAnalyzer(); try { QueryParser qp = new QueryParser( " body " , analyzer); query = qp.parse(queryString); } catch (ParseException e) { } if (searcher != null ) { hits = searcher.search(query); if (hits.length() > 0 ) { System.out.println( " 找到: " + hits.length() + " 个结果! " ); } } } } 其运行结果: 找到: 3 个结果 ! Lucene 其实很简单的,它最主要就是做两件事:建立索引和进行搜索 来看一些在 lucene 中使用的术语,这里并不打算作详细的介绍,只是点一下而已 ----因为这一个世界有一种好东西,叫搜索。 IndexWriter:lucene 中最重要的的类之一,它主要是用来将文档加入索引,同 时控制索引过程中的一些参数使用。 Analyzer:分析器,主要用于分析搜索引擎遇到的各种文本。常用的有 StandardAnalyzer 分析器,StopAnalyzer 分析器,WhitespaceAnalyzer 分 析器等。 Directory:索引存放的位置;lucene 提供了两种索引存放的位置,一种是磁盘, 一种是内存。一般情况将索引放在磁盘上;相应地 lucene 提供了 FSDirectory 和 RAMDirectory 两个类。 Document:文档;Document 相当于一个要进行索引的单元,任何可以想要被 索引的文件都必须转化为 Document 对象才能进行索引。 Field:字段。 IndexSearcher:是 lucene 中最基本的检索工具,所有的检索都会用到 IndexSearcher 工具; Query:查询,lucene 中支持模糊查询,语义查询,短语查询,组合查询等等, 如有 TermQuery,BooleanQuery,RangeQuery,WildcardQuery 等一些类。 QueryParser: 是一个解析用户输入的工具,可以通过扫描用户输入的字符串, 生成 Query 对象。 Hits:在搜索完成之后,需要把搜索结果返回并显示给用户,只有这样才算是完 成搜索的目的。在 lucene 中,搜索的结果的集合是用 Hits 类的实例来表示的。 上面作了一大堆名词解释,下面就看几个简单的实例吧: 1、简单的的 StandardAnalyzer 测试例子 package lighter.javaeye.com; import java.io.IOException; import java.io.StringReader; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Token; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.standard.StandardAnalyzer; public class StandardAnalyzerTest { // 构造函数, public StandardAnalyzerTest() { } public static void main(String[] args) { // 生成一个 StandardAnalyzer 对象 Analyzer aAnalyzer = new StandardAnalyzer(); // 测试字符串 StringReader sr = new StringReader( " lighter javaeye com is the ar e on " ); // 生成 TokenStream 对象 TokenStream ts = aAnalyzer.tokenStream( " name " , sr); try { int i = 0 ; Token t = ts.next(); while (t != null ) { // 辅助输出时显示行号 i ++ ; // 输出处理后的字符 System.out.println( " 第 " + i + " 行: " + t.termText()); // 取得下一个字符 t = ts.next(); } } catch (IOException e) { e.printStackTrace(); } } } 显示结果: 第 1 行:lighter 第 2 行:javaeye 第 3 行:com 提示一下: StandardAnalyzer 是 lucene 中内置的"标准分析器",可以做如下功能: 1、对原有句子按照空格进行了分词 2、所有的大写字母都可以能转换为小写的字母 3、可以去掉一些没有用处的单词,例如"is","the","are"等单词,也删除了所 有的标点 查看一下结果与"new StringReader("lighter javaeye com is the are on")"作一个比较就清楚明了。 这里不对其 API 进行解释了,具体见 lucene 的官方文档。需要注意一点,这里 的代码使用的是 lucene2 的 API,与 1.43 版有一些明显的差别。 2、看另一个实例,简单地建立索引,进行搜索 package lighter.javaeye.com; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.store.FSDirectory; public class FSDirectoryTest { // 建立索引的路径 public static final String path = " c:\\index2 " ; public static void main(String[] args) throws Exception { Document doc1 = new Document(); doc1.add( new Field( " name " , " lighter javaeye com " ,Field.Store.Y ES,Field.Index.TOKENIZED)); Document doc2 = new Document(); doc2.add( new Field( " name " , " lighter blog " ,Field.Store.YES,Field.I ndex.TOKENIZED)); IndexWriter writer = new IndexWriter(FSDirectory.getDirectory(pat h, true ), new StandardAnalyzer(), true ); writer.setMaxFieldLength( 3 ); writer.addDocument(doc1); writer.setMaxFieldLength( 3 ); writer.addDocument(doc2); writer.close(); IndexSearcher searcher = new IndexSearcher(path); Hits hits = null ; Query query = null ; QueryParser qp = new QueryParser( " name " , new StandardAnalyz er()); query = qp.parse( " lighter " ); hits = searcher.search(query); System.out.println( " 查找\ " lighter\ " 共 " + hits.length() + " 个 结果 " ); query = qp.parse( " javaeye " ); hits = searcher.search(query); System.out.println( " 查找\ " javaeye\ " 共 " + hits.length() + " 个 结果 " ); } } 运行结果: 查找 " lighter " 共 2 个结果 查找 " javaeye " 共 1 个结果 到现在我们已经可以用 lucene 建立索引了 下面介绍一下几个功能来完善一下: 1.索引格式 其实索引目录有两种格式, 一种是除配置文件外,每一个 Document 独立成为一个文件(这种搜索起来会 影响速度)。 另一种是全部的 Document 成一个文件,这样属于复合模式就快了。 2.索引文件可放的位置: 索引可以存放在两个地方 1.硬盘,2.内存 放在硬盘上可以用 FSDirectory(),放在内存的用 RAMDirectory()不过一关机 就没了 FSDirectory.getDirectory(File file, boolean create) FSDirectory.getDirectory(String path, boolean create) 两个工厂方法返回目录 New RAMDirectory()就直接可以 再和 IndexWriter(Directory d, Analyzer a, boolean create) 一配合就行了 如: IndexWrtier indexWriter = new IndexWriter(FSDirectory.getDirectory(“c:\\in dex”, true ), new StandardAnlyazer(), true ); IndexWrtier indexWriter = new IndexWriter( new RAMDirectory(), new St andardAnlyazer(), true ); 3.索引的合并 这个可用 IndexWriter.addIndexes(Directory[] dirs) 将目录加进去 来看个例子: public void UniteIndex() throws IOException { IndexWriter writerDisk = new IndexWriter(FSDirectory.getDirectory( " c:\\indexDisk " , true ), new StandardAnalyzer(), true ); Document docDisk = new Document(); docDisk.add( new Field( " name " , " 程序员之家 " ,Field.Store.YES,Field. Index.TOKENIZED)); writerDisk.addDocument(docDisk); RAMDirectory ramDir = new RAMDirectory(); IndexWriter writerRam = new IndexWriter(ramDir, new StandardAnal yzer(), true ); Document docRam = new Document(); docRam.add( new Field( " name " , " 程序员杂志 " ,Field.Store.YES,Field. Index.TOKENIZED)); writerRam.addDocument(docRam); writerRam.close(); // 这个方法非常重要,是必须调用的 writerDisk.addIndexes( new Directory[] {ramDir} ); writerDisk.close(); } public void UniteSearch() throws ParseException, IOException { QueryParser queryParser = new QueryParser( " name " , new Stand ardAnalyzer()); Query query = queryParser.parse( " 程序员 " ); IndexSearcher indexSearcher = new IndexSearcher( " c:\\indexDisk " ); Hits hits = indexSearcher.search(query); System.out.println( " 找到了 " + hits.length() + " 结果 " ); for ( int i = 0 ;i { Document doc = hits.doc(i); System.out.println(doc.get( " name " )); } } 这个例子是将内存中的索引合并到硬盘上来. 注意:合并的时候一定要将被合并的那一方的 IndexWriter 的 close()方法调 用。 4.对索引的其它操作: IndexReader 类是用来操作索引的,它有对 Document,Field 的删除等操作。 下面一部分的内容是:全文的搜索 全文的搜索主要是用:IndexSearcher,Query,Hits,Document(都是 Query 的子类),有的时候用 QueryParser 主要步骤: 1 . new QueryParser(Field 字段, new 分析器) 2 .Query query = QueryParser.parser(“要查询的字串”);这个地方我们可以用反射 ap i 看一下 query 究竟是什么类型 3 . new IndexSearcher(索引目录).search(query);返回 Hits 4 .用 Hits.doc(n);可以遍历出 Document 5 .用 Document 可得到 Field 的具体信息了。 其实 1 ,2 两步就是为了弄出个 Query 实例,究竟是什么类型的看分析器了。 拿以前的例子来说吧 QueryParser queryParser = new QueryParser( " name " , new StandardAn alyzer()); Query query = queryParser.parse( " 程序员 " ); /* 这里返回的就是 org.apache.lucene.search.PhraseQuery */ IndexSearcher indexSearcher = new IndexSearcher( " c:\\indexDisk " ); Hits hits = indexSearcher.search(query); 不管是什么类型,无非返回的就是 Query 的子类,我们完全可以不用这两步直 接 new 个 Query 的子类的实例就 ok 了,不过一般还是用这两步因为它返回的 是 PhraseQuery 这个是非常强大的 query 子类它可以进行多字搜索用 QueryParser 可以设置各个关键字之间的关系这个是最常用的了。 IndexSearcher: 其实 IndexSearcher 它内部自带了一个 IndexReader 用来读取索引的, IndexSearcher 有个 close()方法,这个方法不是用来关闭 IndexSearche 的 是用来关闭自带的 IndexReader。 QueryParser 呢可以用 parser.setOperator()来设置各个关键字之间的关系 (与还是或)它可以自动通过空格从字串里面将关键字分离出来。 注意:用 QueryParser 搜索的时候分析器一定的和建立索引时候用的分析器是 一样的。 Query: 可以看一个 lucene2.0 的帮助文档有很多的子类: BooleanQuery, ConstantScoreQuery, ConstantScoreRangeQuery, DisjunctionMaxQuery, FilteredQuery, MatchAllDocsQuery, MultiPhraseQuery, MultiTermQuery, PhraseQuery, PrefixQuery, RangeQuery, SpanQuery, TermQuery 各自有用法看一下文档就能知道它们的用法了 下面一部分讲一下 lucene 的分析器: 分析器是由分词器和过滤器组成的,拿英文来说吧分词器就是通过空格把单词分 开,过滤器就是把 the,to,of 等词去掉不被搜索和索引。 我们最常用的是 StandardAnalyzer()它是 lucene 的标准分析器它集成了内部 的许多的分析器。 最后一部分了:lucene 的高级搜索了 1.排序 Lucene 有内置的排序用 IndexSearcher.search(query,sort)但是功能并不 理想。我们需要自己实现自定义的排序。 这样的话得实现两个接口: ScoreDocComparator, SortComparatorSource 用 IndexSearcher.search(query,new Sort(new SortField(String Field,SortComparatorSource))); 就看个例子吧: 这是一个建立索引的例子: public void IndexSort() throws IOException { IndexWriter writer = new IndexWriter( " C:\\indexStore " , new Sta ndardAnalyzer(), true ); Document doc = new Document() doc.add( new Field( " sort " , " 1 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); doc = new Document(); doc.add( new Field( " sort " , " 4 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); doc = new Document(); doc.add( new Field( " sort " , " 3 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); doc = new Document(); doc.add( new Field( " sort " , " 5 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); doc = new Document(); doc.add( new Field( " sort " , " 9 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); doc = new Document(); doc.add( new Field( " sort " , " 6 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); doc = new Document(); doc.add( new Field( " sort " , " 7 " ,Field.Store.YES,Field.Index.TOKENI ZED)); writer.addDocument(doc); writer.close(); } 下面是搜索的例子: [code] public void SearchSort1() throws IOException, ParseException { IndexSearcher indexSearcher = new IndexSearcher("C:\\indexStore"); QueryParser queryParser = new QueryParser("sort",new StandardAnalyzer()); Query query = queryParser.parse("4"); Hits hits = indexSearcher.search(query); System.out.println("有"+hits.length()+"个结果"); Document doc = hits.doc(0); System.out.println(doc.get("sort")); } public void SearchSort2() throws IOException, ParseException { IndexSearcher indexSearcher = new IndexSearcher("C:\\indexStore"); Query query = new RangeQuery(new Term("sort","1"),new Term("sort","9"),true);//这个地方前面没有提到,它是用于范围的 Query 可以看一下帮助文档. Hits hits = indexSearcher.search(query,new Sort(new SortField("sort",new MySortComparatorSource()))); System.out.println("有"+hits.length()+"个结果"); for(int i=0;i { Document doc = hits.doc(i); System.out.println(doc.get("sort")); } } public class MyScoreDocComparator implements ScoreDocComparator { private Integer[]sort; public MyScoreDocComparator(String s,IndexReader reader, String fieldname) throws IOException { sort = new Integer[reader.maxDoc()]; for(int i = 0;i { Document doc =reader.document(i); sort[i]=new Integer(doc.get("sort")); } } public int compare(ScoreDoc i, ScoreDoc j) { if(sort[i.doc]>sort[j.doc]) return 1; if(sort[i.doc] return -1; return 0; } public int sortType() { return SortField.INT; } public Comparable sortValue(ScoreDoc i) { // TODO 自动生成方法存根 return new Integer(sort[i.doc]); } } public class MySortComparatorSource implements SortComparatorSource { private static final long serialVersionUID = -9189690812107968361L; public ScoreDocComparator newComparator(IndexReader reader, String fieldname) throws IOException { if(fieldname.equals("sort")) return new MyScoreDocComparator("sort",reader,fieldname); return null; } }[/code] SearchSort1()输出的结果没有排序,SearchSort2()就排序了。 2.多域搜索 MultiFieldQueryParser 如果想输入关键字而不想关心是在哪个 Field 里的就可以用 MultiFieldQueryParser 了 用它的构造函数即可后面的和一个 Field 一样。 MultiFieldQueryParser. parse(String[] queries, String[] fields, BooleanClause.Occur[] flags, Analyzer analyzer) ~~~~~~~~~~~~~~~~~ 第三个参数比较特殊这里也是与以前 lucene1.4.3 不一样的地方 看一个例子就知道了 String[] fields = {"filename", "contents", "description"}; BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD, BooleanClause.Occur.MUST,//在这个 Field 里必须出现的 BooleanClause.Occur.MUST_NOT};//在这个 Field 里不能出 现 MultiFieldQueryParser.parse("query", fields, flags, analyzer); 1、lucene 的索引不能太大,要不然效率会很低。大于 1G 的时候就必须考虑分 布索引的问题 2、不建议用多线程来建索引,产生的互锁问题很麻烦。经常发现索引被 lock, 无法重新建立的情况 3、中文分词是个大问题,目前免费的分词效果都很差。如果有能力还是自己实 现一个分词模块,用最短路径的切分方法,网上有教材和 demo 源码,可以参 考。 4、建增量索引的时候很耗 cpu,在访问量大的时候会导致 cpu 的 idle 为 0 5、默认的评分机制不太合理,需要根据自己的业务定制 整体来说 lucene 要用好不容易,必须在上述方面扩充他的功能,才能作为一个 商用的搜索引擎
还剩18页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

injurewolf

贡献于2012-06-15

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf