Lucene2.9.1使用小结

分类: 搜索引擎 2009-11-26 15:15 413人阅读 评论(1) 收藏 举报

【++yong的博客地址:http://blog.csdn.net/qjyong 】

开源全文搜索工具包Lucene2.9.1的使用。

1. 搭建Lucene的开发环境:在classpath中添加lucene-core-2.9.1.jar包

2. 全文搜索的两个工作: 建立索引文件,搜索索引.

3. Lucene的索引文件逻辑结构
1) 索引(Index)由若干块(片段)(Segment)组成
★2) 块由若干文档(Document)组成: 一个文件映射成一个文档。数据库表中的一条记录映射成一个文档。
★3) 文档由若干域(Field)组成:文件的属性(文件路径,文件的内容)映射成一个域。记录的某个字段映射成一个域。
☆4) 域由若干词(关键字)(Term)组成:文件的属性的内容中某个字符串映射成一个词。

4. Lucene包结构
1) analysis模块:负责词法分析及语言处理而形成Term(词)。提供了一些内置的分析器:最常用的是StandardAnalyzer
2) index模块:负责索引的读写。 对索引文件的segment进行写、合并、优化的IndexWriter类。对索引进行读取和删除操作的IndexReader类。
3) store模块:负责索引的存储。提供索引的各种存储类:FSDirectory,RAMDirectory等。
4) document模块:索引文件内部的基础存储结构封装。如:Document类和Field类等。
5) search模块:负责对索引的搜索。提供了索引搜索器IndexSearcher类和各种Query类,如TermQuery、BooleanQuery等。
6) queryParser模块:负责查询语句的语法分析。提供了解析查询语句的QueryParser类
7) util模块:包含一些公共工具类。

5. 创建索引
1) IndexWriter:索引写出器
a) 构造方法:
IndexWriter(Directory d, Analyzer a, IndexWriter.MaxFieldLength mfl)
如果索引不存在,就会被创建。如果索引存在,就追加.
IndexWriter(Directoryd, Analyzera, booleancreate, IndexWriter.MaxFieldLengthmfl)
create为true时,原索引文件不存在就创建,存在就覆盖。
create为false时,原索引文件不存在就报错,存在就追加。
b) 常用方法:
void addDocument(Document doc); //把指定文档添加到索引写出器中
void iw.close(); //关闭索引写出器,此时才把索引写到目标存储地

2) Directory: 索引存放地。
a) 文件系统:FSDirectory: FSDirectory.open(File file);
b) 内存RAMDirectory: new RAMDirectory();

3) Analyzer: 分词器。
a) StandardAnalyzer: 标准分词器。对英文采用空白, 标点符号进行分词。对中文采用单字分词。
b) SmartChineseAnalyzer: 智能中文分词器。(LUCENE_HOME/contrib/analyzers/smartcn/lucene-smartcn-2.9.1.jar)
C) 第三方的中文分词器:如PaodingAnalyzer、IKAnalyzer

4) IndexWriter.MaxFieldLength: 指定域值的最大长度。
a) UNLIMITED 无限制的。
b) LIMITED 有限制的。值为10000

5) Document: 索引的组成单元. 一组Field的集合.
a) 构造方法: Document();
b) 常用方法: void add(Field f); //添加指定域到这个文档中

6) Field: 域,代表文档的某个索引域.
a) 构造方法: Field(String name, String value, Field.Store.YES, Field.Index.ANALYZED)
name: 域的名称, 只能是字符串.
value: 域的值, 只能是字符串.
Field.Store: 指定Field的值是否存储或怎样存储. NO(不存储), YES(存储),COMPRESS(压缩后存储)
Field.Index: 指定Field是否被索引或怎么被索引. NO(不索引), ANALYZED(分词后索引), NOT_ANALYZED(不分词直接索引)
7) 示例代码:

  1. //src要创建索引的文件,destDir索引存放的目录
  2. public static void createIndex(Filesrc,FiledestDir){
  3. Analyzeranalyzer=new StandardAnalyzer(Version.LUCENE_CURRENT); //创建一个语法分析器
  4. IndexWriteriwriter=null ;
  5. Directorydirectory=null ;
  6. try {
  7. directory=FSDirectory.open(destDir);//把索引文件存储到磁盘目录
  8. //创建一个IndexWriter(存放索引文件的目录,分析器,Field的最大长度)
  9. iwriter=new IndexWriter(directory,analyzer, true ,IndexWriter.MaxFieldLength.UNLIMITED);
  10. //iwriter.setUseCompoundFile(true);//使用复合文件
  11. Documentdoc=new Document(); //创建一个Document对象
  12. //把文件路径作为"path"域:不分词,索引,保存
  13. doc.add(new Field( "path" ,src.getCanonicalPath(),Field.Store.YES,Field.Index.NOT_ANALYZED));
  14. StringBuildersb=new StringBuilder();
  15. BufferedReaderbr=new BufferedReader( new FileReader(src));
  16. for (Stringstr= null ;(str=br.readLine())!= null ;){
  17. sb.append(str).append(System.getProperty("line.separator" ));
  18. }
  19. //文件内容作为"content"域:分词,索引,保存
  20. doc.add(new Field( "contents" ,sb.toString(),Field.Store.YES,Field.Index.ANALYZED));
  21. iwriter.addDocument(doc);//把Document存放到IndexWriter中
  22. iwriter.optimize();//对索引进行优化
  23. }catch (IOExceptione){
  24. e.printStackTrace();
  25. }finally {
  26. if (iwriter!= null ){
  27. try {
  28. iwriter.close();//关闭IndexWriter时,才把内存中的数据写到文件
  29. }catch (IOExceptione){
  30. e.printStackTrace();
  31. }
  32. }
  33. if (directory!= null ){
  34. try {
  35. directory.close();//关闭索引存放目录
  36. }catch (IOExceptione){
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  41. }
  1. //src要创建索引的文件,destDir索引存放的目录
  2. publicstaticvoidcreateIndex(Filesrc,FiledestDir){
  3. Analyzeranalyzer=newStandardAnalyzer(Version.LUCENE_CURRENT);//创建一个语法分析器
  4. IndexWriteriwriter=null;
  5. Directorydirectory=null;
  6. try{
  7. directory=FSDirectory.open(destDir);//把索引文件存储到磁盘目录
  8. //创建一个IndexWriter(存放索引文件的目录,分析器,Field的最大长度)
  9. iwriter=newIndexWriter(directory,analyzer,true,IndexWriter.MaxFieldLength.UNLIMITED);
  10. //iwriter.setUseCompoundFile(true);//使用复合文件
  11. Documentdoc=newDocument();//创建一个Document对象
  12. //把文件路径作为"path"域:不分词,索引,保存
  13. doc.add(newField("path",src.getCanonicalPath(),Field.Store.YES,Field.Index.NOT_ANALYZED));
  14. StringBuildersb=newStringBuilder();
  15. BufferedReaderbr=newBufferedReader(newFileReader(src));
  16. for(Stringstr=null;(str=br.readLine())!=null;){
  17. sb.append(str).append(System.getProperty("line.separator"));
  18. }
  19. //文件内容作为"content"域:分词,索引,保存
  20. doc.add(newField("contents",sb.toString(),Field.Store.YES,Field.Index.ANALYZED));
  21. iwriter.addDocument(doc);//把Document存放到IndexWriter中
  22. iwriter.optimize();//对索引进行优化
  23. }catch(IOExceptione){
  24. e.printStackTrace();
  25. }finally{
  26. if(iwriter!=null){
  27. try{
  28. iwriter.close();//关闭IndexWriter时,才把内存中的数据写到文件
  29. }catch(IOExceptione){
  30. e.printStackTrace();
  31. }
  32. }
  33. if(directory!=null){
  34. try{
  35. directory.close();//关闭索引存放目录
  36. }catch(IOExceptione){
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  41. }

//src要创建索引的文件,destDir索引存放的目录 public static void createIndex(File src, File destDir){ Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT); //创建一个语法分析器 IndexWriter iwriter = null; Directory directory = null; try { directory = FSDirectory.open(destDir); //把索引文件存储到磁盘目录 //创建一个IndexWriter(存放索引文件的目录,分析器,Field的最大长度) iwriter = new IndexWriter(directory, analyzer,true, IndexWriter.MaxFieldLength.UNLIMITED); //iwriter.setUseCompoundFile(true);//使用复合文件 Document doc = new Document(); //创建一个Document对象 //把文件路径作为"path"域:不分词,索引,保存 doc.add(new Field("path", src.getCanonicalPath(), Field.Store.YES, Field.Index.NOT_ANALYZED)); StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(new FileReader(src)); for(String str = null; (str = br.readLine())!=null;){ sb.append(str).append(System.getProperty("line.separator")); } //文件内容作为"content"域:分词,索引,保存 doc.add(new Field("contents", sb.toString(), Field.Store.YES, Field.Index.ANALYZED)); iwriter.addDocument(doc); //把Document存放到IndexWriter中 iwriter.optimize(); //对索引进行优化 } catch (IOException e) { e.printStackTrace(); } finally { if (iwriter != null) { try { iwriter.close(); //关闭IndexWriter时,才把内存中的数据写到文件 } catch (IOException e) { e.printStackTrace(); } } if (directory != null) { try { directory.close(); //关闭索引存放目录 } catch (IOException e) { e.printStackTrace(); } } } }

6. 查询索引
1) IndexSearcher: 索引查询器
a) 构造器: IndexSearcher(Directorypath, booleanreadOnly)
b) 常用方法:
TopDocs search(Query query, Filter filter, int n); //执行查询。n指的是最多返回的Document的数量。
Document doc(int文件内部编号); //根据文档的内部编号获取到该Document
void close(); //关闭查询器
2) Query: 查询对象。把用户输入的查询字符串封装成Lucene能够识别的Query对象。
3) Filter: 用来过虑搜索结果的对象。
4) TopDocs: 代表查询结果集信息对象。它有两个属性:
a) totalHits: 查询命中数。
b) scoreDocs: 查询结果信息。它包含符合条件的Document的内部编号(doc)及评分(score)。
5) 示例代码:

  1. //keyword要搜索的关键字。indexDir索引存放的目录
  2. public static void searcher(Stringkeyword,FileindexDir){
  3. IndexSearcherisearcher=null ;
  4. Directorydirectory=null ;
  5. try {
  6. Analyzeranalyzer=new StandardAnalyzer(Version.LUCENE_CURRENT);
  7. directory=FSDirectory.open(indexDir);
  8. //创建解析器
  9. QueryParserparser=new QueryParser(Version.LUCENE_CURRENT, "contents" ,analyzer);
  10. Queryquery=parser.parse(keyword);//获取查询对象
  11. //Queryquery1=newTermQuery(newTerm("contents",keyword));
  12. //Queryquery2=newTermQuery(newTerm("contents",keyword2));
  13. //BooleanQueryquery=newBooleanQuery();
  14. //query.add(query1,Occur.SHOULD);
  15. //query.add(query2,Occur.SHOULD);
  16. //QueryParserparser=newMultiFieldQueryParser(Version.LUCENE_CURRENT,newString[]{"path","contents"},analyzer);
  17. //Queryquery=parser.parse(keyword);
  18. isearcher=new IndexSearcher(directory, true ); //创建索引搜索器
  19. TopDocsts=isearcher.search(query,null , 100 ); //执行搜索,获取查询结果集对象
  20. int totalHits=ts.totalHits; //获取命中数
  21. System.out.println("命中数:" +totalHits);
  22. ScoreDoc[]hits=ts.scoreDocs;//获取命中的文档信息对象
  23. for ( int i= 0 ;i<hits.length;i++){
  24. DocumenthitDoc=isearcher.doc(hits[i].doc);//根据命中的文档的内部编号获取该文档
  25. System.out.println(hitDoc.getField("contents" ).stringValue()); //输出该文档指定域的值
  26. }
  27. }catch (IOExceptione){
  28. e.printStackTrace();
  29. }catch (ParseExceptione){
  30. e.printStackTrace();
  31. }finally {
  32. if (isearcher!= null ){
  33. try {
  34. isearcher.close();//关闭搜索器
  35. }catch (IOExceptione){
  36. e.printStackTrace();
  37. }
  38. }
  39. if (directory!= null ){
  40. try {
  41. directory.close();//关闭索引存放目录
  42. }catch (IOExceptione){
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }
  1. //keyword要搜索的关键字。indexDir索引存放的目录
  2. publicstaticvoidsearcher(Stringkeyword,FileindexDir){
  3. IndexSearcherisearcher=null;
  4. Directorydirectory=null;
  5. try{
  6. Analyzeranalyzer=newStandardAnalyzer(Version.LUCENE_CURRENT);
  7. directory=FSDirectory.open(indexDir);
  8. //创建解析器
  9. QueryParserparser=newQueryParser(Version.LUCENE_CURRENT,"contents",analyzer);
  10. Queryquery=parser.parse(keyword);//获取查询对象
  11. //Queryquery1=newTermQuery(newTerm("contents",keyword));
  12. //Queryquery2=newTermQuery(newTerm("contents",keyword2));
  13. //BooleanQueryquery=newBooleanQuery();
  14. //query.add(query1,Occur.SHOULD);
  15. //query.add(query2,Occur.SHOULD);
  16. //QueryParserparser=newMultiFieldQueryParser(Version.LUCENE_CURRENT,newString[]{"path","contents"},analyzer);
  17. //Queryquery=parser.parse(keyword);
  18. isearcher=newIndexSearcher(directory,true);//创建索引搜索器
  19. TopDocsts=isearcher.search(query,null,100);//执行搜索,获取查询结果集对象
  20. inttotalHits=ts.totalHits;//获取命中数
  21. System.out.println("命中数:"+totalHits);
  22. ScoreDoc[]hits=ts.scoreDocs;//获取命中的文档信息对象
  23. for(inti=0;i<hits.length;i++){
  24. DocumenthitDoc=isearcher.doc(hits[i].doc);//根据命中的文档的内部编号获取该文档
  25. System.out.println(hitDoc.getField("contents").stringValue());//输出该文档指定域的值
  26. }
  27. }catch(IOExceptione){
  28. e.printStackTrace();
  29. }catch(ParseExceptione){
  30. e.printStackTrace();
  31. }finally{
  32. if(isearcher!=null){
  33. try{
  34. isearcher.close();//关闭搜索器
  35. }catch(IOExceptione){
  36. e.printStackTrace();
  37. }
  38. }
  39. if(directory!=null){
  40. try{
  41. directory.close();//关闭索引存放目录
  42. }catch(IOExceptione){
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }

//keyword要搜索的关键字。indexDir索引存放的目录 public static void searcher(String keyword, File indexDir){ IndexSearcher isearcher = null; Directory directory = null; try{ Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT); directory = FSDirectory.open(indexDir); //创建解析器 QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "contents", analyzer); Query query = parser.parse(keyword);//获取查询对象 // Query query1 = new TermQuery(new Term("contents", keyword)); // Query query2 = new TermQuery(new Term("contents", keyword2)); // BooleanQuery query = new BooleanQuery(); // query.add(query1, Occur.SHOULD); // query.add(query2, Occur.SHOULD); // QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{"path", "contents"}, analyzer); // Query query = parser.parse(keyword); isearcher = new IndexSearcher(directory, true); //创建索引搜索器 TopDocs ts = isearcher.search(query, null, 100); //执行搜索,获取查询结果集对象 int totalHits = ts.totalHits; //获取命中数 System.out.println("命中数:" + totalHits); ScoreDoc[] hits = ts.scoreDocs; //获取命中的文档信息对象 for (int i = 0; i < hits.length; i++) { Document hitDoc = isearcher.doc(hits[i].doc); //根据命中的文档的内部编号获取该文档 System.out.println(hitDoc.getField("contents").stringValue()); //输出该文档指定域的值 } } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } finally { if (isearcher != null) { try { isearcher.close(); //关闭搜索器 } catch (IOException e) { e.printStackTrace(); } } if (directory != null) { try { directory.close(); //关闭索引存放目录 } catch (IOException e) { e.printStackTrace(); } } } }

7. 删除索引
IndexWriter提供deleteDocuments(Term term); //会删除索引文件里含有指定Term的所有Document。
IndexReader也提供了deleteDocuments(Term term);

8. 更新索引
IndexWriter提供updateDocument(Term term, Document doc); //实际上是先删除再创建索引。

9. 常用查询器
1) TermQuery : 按Term(关键字)查询。构造方法:TermQuery(Termt)

  1. Queryquery= new TermQuery( new Term( "contents" ,keyword));
  2. isearcher=new IndexSearcher(FSDirectory.open(indexDir), true );
  3. TopDocsts=isearcher.search(query,null , 100 );
  1. Queryquery=newTermQuery(newTerm("contents",keyword));
  2. isearcher=newIndexSearcher(FSDirectory.open(indexDir),true);
  3. TopDocsts=isearcher.search(query,null,100);

Query query = new TermQuery(new Term("contents", keyword)); isearcher = new IndexSearcher(FSDirectory.open(indexDir), true); TopDocs ts = isearcher.search(query, null, 100);

2) BooleanQuery: 布尔查询。组合多个查询器。

  1. Queryquery1= new TermQuery( new Term( "contents" ,keyword));
  2. Queryquery2=new TermQuery( new Term( "contents" ,keyword2));
  3. BooleanQueryquery=new BooleanQuery();
  4. query.add(query1,Occur.SHOULD);
  5. query.add(query2,Occur.SHOULD);
  6. isearcher=new IndexSearcher(directory, true );
  7. TopDocsts=isearcher.search(query,null , 100 );
  1. Queryquery1=newTermQuery(newTerm("contents",keyword));
  2. Queryquery2=newTermQuery(newTerm("contents",keyword2));
  3. BooleanQueryquery=newBooleanQuery();
  4. query.add(query1,Occur.SHOULD);
  5. query.add(query2,Occur.SHOULD);
  6. isearcher=newIndexSearcher(directory,true);
  7. TopDocsts=isearcher.search(query,null,100);

Query query1 = new TermQuery(new Term("contents", keyword)); Query query2 = new TermQuery(new Term("contents", keyword2)); BooleanQuery query = new BooleanQuery(); query.add(query1, Occur.SHOULD); query.add(query2, Occur.SHOULD); isearcher = new IndexSearcher(directory, true); TopDocs ts = isearcher.search(query, null, 100);

3) MultiFieldQueryParser: 多Field中查询。

  1. QueryParserparser= new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{ "path" , "contents" },analyzer);
  2. Queryquery=parser.parse(keyword);
  3. isearcher=new IndexSearcher(FSDirectory.open(indexDir), true );
  4. TopDocsts=isearcher.search(query,null , 100 );
  1. QueryParserparser=newMultiFieldQueryParser(Version.LUCENE_CURRENT,newString[]{"path","contents"},analyzer);
  2. Queryquery=parser.parse(keyword);
  3. isearcher=newIndexSearcher(FSDirectory.open(indexDir),true);
  4. TopDocsts=isearcher.search(query,null,100);

QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{"path", "contents"}, analyzer); Query query = parser.parse(keyword); isearcher = new IndexSearcher(FSDirectory.open(indexDir), true); TopDocs ts = isearcher.search(query, null, 100);

10. 高亮器Highlighter:在网页中对搜索结果予以高亮显示。
1) 在classpath添加contrib/highlighter/lucene-highlighter-2.9.1.jar
2) 示例伪代码

  1. SimpleHTMLFormattershf= new SimpleHTMLFormatter( "<spanstyle=" color:red "mce_style=" color:red ">" , "</span>" ); //默认是<b>..</b>
  2. //构造高亮器:指定高亮的格式,指定查询计分器
  3. Highlighterhighlighter=new Highlighter(shf, new QueryScorer(query));
  4. //设置块划分器
  5. highlighter.setTextFragmenter(new SimpleFragmenter(Integer.MAX_VALUE));
  6. Stringcontent=highlighter.getBestFragment(Analyzer,"fieldName" , "fieldValue" );
  1. SimpleHTMLFormattershf=newSimpleHTMLFormatter("<span
  2. style="color:red"mce_style="color:red">","</span>");
  3. //默认是<b>..</b>//构造高亮器:指定高亮的格式,指定查询计分器Highlighter
  4. highlighter=newHighlighter(shf,newQueryScorer(query));//设置块划分器
  5. highlighter.setTextFragmenter(newSimpleFragmenter(Integer.MAX_VALUE));
  6. Stringcontent=highlighter.getBestFragment(Analyzer,"fieldName",
  7. "fieldValue");

SimpleHTMLFormatter shf = new SimpleHTMLFormatter("<span style="color:red" mce_style="color:red">", "</span>"); //默认是<b>..</b> // 构造高亮器:指定高亮的格式,指定查询计分器 Highlighter highlighter = new Highlighter(shf, new QueryScorer(query)); //设置块划分器 highlighter.setTextFragmenter(new SimpleFragmenter(Integer.MAX_VALUE)); String content = highlighter.getBestFragment(Analyzer, "fieldName", "fieldValue");

11. 优化
1) 使用IndexWriter须注意
修改索引后,需flush()或close()方能生效
非线程安全,任一时刻仅能有一个线程对其操作.
2) 使用IndexSearcher须注意
一旦打开,不会搜索到以后添加的索引
线程安全,多个线程仅需一个实例
3) 最佳实践
多个线程共享一个IndexSearcher, 只有当索引修改后才重新打开IndexSearcher
多个线程共享一个IndexWriter并严格同步
异步修改索引提高性能(JMS)
为每个Document创建单独的索引目录

12. 在emall项目中整合Lucene对产品的ID,名称和描述进行全文搜索。

13. 使用Compass简化Lucene操作。(未完待续)

【++yong的博客地址:http://blog.csdn.net/qjyong 】

开源全文搜索工具包Lucene2.9.1的使用。

1. 搭建Lucene的开发环境:在classpath中添加lucene-core-2.9.1.jar包

2. 全文搜索的两个工作: 建立索引文件,搜索索引.

3. Lucene的索引文件逻辑结构
1) 索引(Index)由若干块(片段)(Segment)组成
★2) 块由若干文档(Document)组成: 一个文件映射成一个文档。数据库表中的一条记录映射成一个文档。
★3) 文档由若干域(Field)组成:文件的属性(文件路径,文件的内容)映射成一个域。记录的某个字段映射成一个域。
☆4) 域由若干词(关键字)(Term)组成:文件的属性的内容中某个字符串映射成一个词。

4. Lucene包结构
1) analysis模块:负责词法分析及语言处理而形成Term(词)。提供了一些内置的分析器:最常用的是StandardAnalyzer
2) index模块:负责索引的读写。 对索引文件的segment进行写、合并、优化的IndexWriter类。对索引进行读取和删除操作的IndexReader类。
3) store模块:负责索引的存储。提供索引的各种存储类:FSDirectory,RAMDirectory等。
4) document模块:索引文件内部的基础存储结构封装。如:Document类和Field类等。
5) search模块:负责对索引的搜索。提供了索引搜索器IndexSearcher类和各种Query类,如TermQuery、BooleanQuery等。
6) queryParser模块:负责查询语句的语法分析。提供了解析查询语句的QueryParser类
7) util模块:包含一些公共工具类。

5. 创建索引
1) IndexWriter:索引写出器
a) 构造方法:
IndexWriter(Directory d, Analyzer a, IndexWriter.MaxFieldLength mfl)
如果索引不存在,就会被创建。如果索引存在,就追加.
IndexWriter(Directoryd, Analyzera, booleancreate, IndexWriter.MaxFieldLengthmfl)
create为true时,原索引文件不存在就创建,存在就覆盖。
create为false时,原索引文件不存在就报错,存在就追加。
b) 常用方法:
void addDocument(Document doc); //把指定文档添加到索引写出器中
void iw.close(); //关闭索引写出器,此时才把索引写到目标存储地

2) Directory: 索引存放地。
a) 文件系统:FSDirectory: FSDirectory.open(File file);
b) 内存RAMDirectory: new RAMDirectory();

3) Analyzer: 分词器。
a) StandardAnalyzer: 标准分词器。对英文采用空白, 标点符号进行分词。对中文采用单字分词。
b) SmartChineseAnalyzer: 智能中文分词器。(LUCENE_HOME/contrib/analyzers/smartcn/lucene-smartcn-2.9.1.jar)
C) 第三方的中文分词器:如PaodingAnalyzer、IKAnalyzer

4) IndexWriter.MaxFieldLength: 指定域值的最大长度。
a) UNLIMITED 无限制的。
b) LIMITED 有限制的。值为10000

5) Document: 索引的组成单元. 一组Field的集合.
a) 构造方法: Document();
b) 常用方法: void add(Field f); //添加指定域到这个文档中

6) Field: 域,代表文档的某个索引域.
a) 构造方法: Field(String name, String value, Field.Store.YES, Field.Index.ANALYZED)
name: 域的名称, 只能是字符串.
value: 域的值, 只能是字符串.
Field.Store: 指定Field的值是否存储或怎样存储. NO(不存储), YES(存储),COMPRESS(压缩后存储)
Field.Index: 指定Field是否被索引或怎么被索引. NO(不索引), ANALYZED(分词后索引), NOT_ANALYZED(不分词直接索引)
7) 示例代码:

  1. //src要创建索引的文件,destDir索引存放的目录
  2. public static void createIndex(Filesrc,FiledestDir){
  3. Analyzeranalyzer=new StandardAnalyzer(Version.LUCENE_CURRENT); //创建一个语法分析器
  4. IndexWriteriwriter=null ;
  5. Directorydirectory=null ;
  6. try {
  7. directory=FSDirectory.open(destDir);//把索引文件存储到磁盘目录
  8. //创建一个IndexWriter(存放索引文件的目录,分析器,Field的最大长度)
  9. iwriter=new IndexWriter(directory,analyzer, true ,IndexWriter.MaxFieldLength.UNLIMITED);
  10. //iwriter.setUseCompoundFile(true);//使用复合文件
  11. Documentdoc=new Document(); //创建一个Document对象
  12. //把文件路径作为"path"域:不分词,索引,保存
  13. doc.add(new Field( "path" ,src.getCanonicalPath(),Field.Store.YES,Field.Index.NOT_ANALYZED));
  14. StringBuildersb=new StringBuilder();
  15. BufferedReaderbr=new BufferedReader( new FileReader(src));
  16. for (Stringstr= null ;(str=br.readLine())!= null ;){
  17. sb.append(str).append(System.getProperty("line.separator" ));
  18. }
  19. //文件内容作为"content"域:分词,索引,保存
  20. doc.add(new Field( "contents" ,sb.toString(),Field.Store.YES,Field.Index.ANALYZED));
  21. iwriter.addDocument(doc);//把Document存放到IndexWriter中
  22. iwriter.optimize();//对索引进行优化
  23. }catch (IOExceptione){
  24. e.printStackTrace();
  25. }finally {
  26. if (iwriter!= null ){
  27. try {
  28. iwriter.close();//关闭IndexWriter时,才把内存中的数据写到文件
  29. }catch (IOExceptione){
  30. e.printStackTrace();
  31. }
  32. }
  33. if (directory!= null ){
  34. try {
  35. directory.close();//关闭索引存放目录
  36. }catch (IOExceptione){
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  41. }
  1. //src要创建索引的文件,destDir索引存放的目录
  2. publicstaticvoidcreateIndex(Filesrc,FiledestDir){
  3. Analyzeranalyzer=newStandardAnalyzer(Version.LUCENE_CURRENT);//创建一个语法分析器
  4. IndexWriteriwriter=null;
  5. Directorydirectory=null;
  6. try{
  7. directory=FSDirectory.open(destDir);//把索引文件存储到磁盘目录
  8. //创建一个IndexWriter(存放索引文件的目录,分析器,Field的最大长度)
  9. iwriter=newIndexWriter(directory,analyzer,true,IndexWriter.MaxFieldLength.UNLIMITED);
  10. //iwriter.setUseCompoundFile(true);//使用复合文件
  11. Documentdoc=newDocument();//创建一个Document对象
  12. //把文件路径作为"path"域:不分词,索引,保存
  13. doc.add(newField("path",src.getCanonicalPath(),Field.Store.YES,Field.Index.NOT_ANALYZED));
  14. StringBuildersb=newStringBuilder();
  15. BufferedReaderbr=newBufferedReader(newFileReader(src));
  16. for(Stringstr=null;(str=br.readLine())!=null;){
  17. sb.append(str).append(System.getProperty("line.separator"));
  18. }
  19. //文件内容作为"content"域:分词,索引,保存
  20. doc.add(newField("contents",sb.toString(),Field.Store.YES,Field.Index.ANALYZED));
  21. iwriter.addDocument(doc);//把Document存放到IndexWriter中
  22. iwriter.optimize();//对索引进行优化
  23. }catch(IOExceptione){
  24. e.printStackTrace();
  25. }finally{
  26. if(iwriter!=null){
  27. try{
  28. iwriter.close();//关闭IndexWriter时,才把内存中的数据写到文件
  29. }catch(IOExceptione){
  30. e.printStackTrace();
  31. }
  32. }
  33. if(directory!=null){
  34. try{
  35. directory.close();//关闭索引存放目录
  36. }catch(IOExceptione){
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  41. }

//src要创建索引的文件,destDir索引存放的目录 public static void createIndex(File src, File destDir){ Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT); //创建一个语法分析器 IndexWriter iwriter = null; Directory directory = null; try { directory = FSDirectory.open(destDir); //把索引文件存储到磁盘目录 //创建一个IndexWriter(存放索引文件的目录,分析器,Field的最大长度) iwriter = new IndexWriter(directory, analyzer,true, IndexWriter.MaxFieldLength.UNLIMITED); //iwriter.setUseCompoundFile(true);//使用复合文件 Document doc = new Document(); //创建一个Document对象 //把文件路径作为"path"域:不分词,索引,保存 doc.add(new Field("path", src.getCanonicalPath(), Field.Store.YES, Field.Index.NOT_ANALYZED)); StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(new FileReader(src)); for(String str = null; (str = br.readLine())!=null;){ sb.append(str).append(System.getProperty("line.separator")); } //文件内容作为"content"域:分词,索引,保存 doc.add(new Field("contents", sb.toString(), Field.Store.YES, Field.Index.ANALYZED)); iwriter.addDocument(doc); //把Document存放到IndexWriter中 iwriter.optimize(); //对索引进行优化 } catch (IOException e) { e.printStackTrace(); } finally { if (iwriter != null) { try { iwriter.close(); //关闭IndexWriter时,才把内存中的数据写到文件 } catch (IOException e) { e.printStackTrace(); } } if (directory != null) { try { directory.close(); //关闭索引存放目录 } catch (IOException e) { e.printStackTrace(); } } } }

6. 查询索引
1) IndexSearcher: 索引查询器
a) 构造器: IndexSearcher(Directorypath, booleanreadOnly)
b) 常用方法:
TopDocs search(Query query, Filter filter, int n); //执行查询。n指的是最多返回的Document的数量。
Document doc(int文件内部编号); //根据文档的内部编号获取到该Document
void close(); //关闭查询器
2) Query: 查询对象。把用户输入的查询字符串封装成Lucene能够识别的Query对象。
3) Filter: 用来过虑搜索结果的对象。
4) TopDocs: 代表查询结果集信息对象。它有两个属性:
a) totalHits: 查询命中数。
b) scoreDocs: 查询结果信息。它包含符合条件的Document的内部编号(doc)及评分(score)。
5) 示例代码:

  1. //keyword要搜索的关键字。indexDir索引存放的目录
  2. public static void searcher(Stringkeyword,FileindexDir){
  3. IndexSearcherisearcher=null ;
  4. Directorydirectory=null ;
  5. try {
  6. Analyzeranalyzer=new StandardAnalyzer(Version.LUCENE_CURRENT);
  7. directory=FSDirectory.open(indexDir);
  8. //创建解析器
  9. QueryParserparser=new QueryParser(Version.LUCENE_CURRENT, "contents" ,analyzer);
  10. Queryquery=parser.parse(keyword);//获取查询对象
  11. //Queryquery1=newTermQuery(newTerm("contents",keyword));
  12. //Queryquery2=newTermQuery(newTerm("contents",keyword2));
  13. //BooleanQueryquery=newBooleanQuery();
  14. //query.add(query1,Occur.SHOULD);
  15. //query.add(query2,Occur.SHOULD);
  16. //QueryParserparser=newMultiFieldQueryParser(Version.LUCENE_CURRENT,newString[]{"path","contents"},analyzer);
  17. //Queryquery=parser.parse(keyword);
  18. isearcher=new IndexSearcher(directory, true ); //创建索引搜索器
  19. TopDocsts=isearcher.search(query,null , 100 ); //执行搜索,获取查询结果集对象
  20. int totalHits=ts.totalHits; //获取命中数
  21. System.out.println("命中数:" +totalHits);
  22. ScoreDoc[]hits=ts.scoreDocs;//获取命中的文档信息对象
  23. for ( int i= 0 ;i<hits.length;i++){
  24. DocumenthitDoc=isearcher.doc(hits[i].doc);//根据命中的文档的内部编号获取该文档
  25. System.out.println(hitDoc.getField("contents" ).stringValue()); //输出该文档指定域的值
  26. }
  27. }catch (IOExceptione){
  28. e.printStackTrace();
  29. }catch (ParseExceptione){
  30. e.printStackTrace();
  31. }finally {
  32. if (isearcher!= null ){
  33. try {
  34. isearcher.close();//关闭搜索器
  35. }catch (IOExceptione){
  36. e.printStackTrace();
  37. }
  38. }
  39. if (directory!= null ){
  40. try {
  41. directory.close();//关闭索引存放目录
  42. }catch (IOExceptione){
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }
  1. //keyword要搜索的关键字。indexDir索引存放的目录
  2. publicstaticvoidsearcher(Stringkeyword,FileindexDir){
  3. IndexSearcherisearcher=null;
  4. Directorydirectory=null;
  5. try{
  6. Analyzeranalyzer=newStandardAnalyzer(Version.LUCENE_CURRENT);
  7. directory=FSDirectory.open(indexDir);
  8. //创建解析器
  9. QueryParserparser=newQueryParser(Version.LUCENE_CURRENT,"contents",analyzer);
  10. Queryquery=parser.parse(keyword);//获取查询对象
  11. //Queryquery1=newTermQuery(newTerm("contents",keyword));
  12. //Queryquery2=newTermQuery(newTerm("contents",keyword2));
  13. //BooleanQueryquery=newBooleanQuery();
  14. //query.add(query1,Occur.SHOULD);
  15. //query.add(query2,Occur.SHOULD);
  16. //QueryParserparser=newMultiFieldQueryParser(Version.LUCENE_CURRENT,newString[]{"path","contents"},analyzer);
  17. //Queryquery=parser.parse(keyword);
  18. isearcher=newIndexSearcher(directory,true);//创建索引搜索器
  19. TopDocsts=isearcher.search(query,null,100);//执行搜索,获取查询结果集对象
  20. inttotalHits=ts.totalHits;//获取命中数
  21. System.out.println("命中数:"+totalHits);
  22. ScoreDoc[]hits=ts.scoreDocs;//获取命中的文档信息对象
  23. for(inti=0;i<hits.length;i++){
  24. DocumenthitDoc=isearcher.doc(hits[i].doc);//根据命中的文档的内部编号获取该文档
  25. System.out.println(hitDoc.getField("contents").stringValue());//输出该文档指定域的值
  26. }
  27. }catch(IOExceptione){
  28. e.printStackTrace();
  29. }catch(ParseExceptione){
  30. e.printStackTrace();
  31. }finally{
  32. if(isearcher!=null){
  33. try{
  34. isearcher.close();//关闭搜索器
  35. }catch(IOExceptione){
  36. e.printStackTrace();
  37. }
  38. }
  39. if(directory!=null){
  40. try{
  41. directory.close();//关闭索引存放目录
  42. }catch(IOExceptione){
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }

//keyword要搜索的关键字。indexDir索引存放的目录 public static void searcher(String keyword, File indexDir){ IndexSearcher isearcher = null; Directory directory = null; try{ Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT); directory = FSDirectory.open(indexDir); //创建解析器 QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "contents", analyzer); Query query = parser.parse(keyword);//获取查询对象 // Query query1 = new TermQuery(new Term("contents", keyword)); // Query query2 = new TermQuery(new Term("contents", keyword2)); // BooleanQuery query = new BooleanQuery(); // query.add(query1, Occur.SHOULD); // query.add(query2, Occur.SHOULD); // QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{"path", "contents"}, analyzer); // Query query = parser.parse(keyword); isearcher = new IndexSearcher(directory, true); //创建索引搜索器 TopDocs ts = isearcher.search(query, null, 100); //执行搜索,获取查询结果集对象 int totalHits = ts.totalHits; //获取命中数 System.out.println("命中数:" + totalHits); ScoreDoc[] hits = ts.scoreDocs; //获取命中的文档信息对象 for (int i = 0; i < hits.length; i++) { Document hitDoc = isearcher.doc(hits[i].doc); //根据命中的文档的内部编号获取该文档 System.out.println(hitDoc.getField("contents").stringValue()); //输出该文档指定域的值 } } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } finally { if (isearcher != null) { try { isearcher.close(); //关闭搜索器 } catch (IOException e) { e.printStackTrace(); } } if (directory != null) { try { directory.close(); //关闭索引存放目录 } catch (IOException e) { e.printStackTrace(); } } } }

7. 删除索引
IndexWriter提供deleteDocuments(Term term); //会删除索引文件里含有指定Term的所有Document。
IndexReader也提供了deleteDocuments(Term term);

8. 更新索引
IndexWriter提供updateDocument(Term term, Document doc); //实际上是先删除再创建索引。

9. 常用查询器
1) TermQuery : 按Term(关键字)查询。构造方法:TermQuery(Termt)

  1. Queryquery= new TermQuery( new Term( "contents" ,keyword));
  2. isearcher=new IndexSearcher(FSDirectory.open(indexDir), true );
  3. TopDocsts=isearcher.search(query,null , 100 );
  1. Queryquery=newTermQuery(newTerm("contents",keyword));
  2. isearcher=newIndexSearcher(FSDirectory.open(indexDir),true);
  3. TopDocsts=isearcher.search(query,null,100);

Query query = new TermQuery(new Term("contents", keyword)); isearcher = new IndexSearcher(FSDirectory.open(indexDir), true); TopDocs ts = isearcher.search(query, null, 100);

2) BooleanQuery: 布尔查询。组合多个查询器。

  1. Queryquery1= new TermQuery( new Term( "contents" ,keyword));
  2. Queryquery2=new TermQuery( new Term( "contents" ,keyword2));
  3. BooleanQueryquery=new BooleanQuery();
  4. query.add(query1,Occur.SHOULD);
  5. query.add(query2,Occur.SHOULD);
  6. isearcher=new IndexSearcher(directory, true );
  7. TopDocsts=isearcher.search(query,null , 100 );
  1. Queryquery1=newTermQuery(newTerm("contents",keyword));
  2. Queryquery2=newTermQuery(newTerm("contents",keyword2));
  3. BooleanQueryquery=newBooleanQuery();
  4. query.add(query1,Occur.SHOULD);
  5. query.add(query2,Occur.SHOULD);
  6. isearcher=newIndexSearcher(directory,true);
  7. TopDocsts=isearcher.search(query,null,100);

Query query1 = new TermQuery(new Term("contents", keyword)); Query query2 = new TermQuery(new Term("contents", keyword2)); BooleanQuery query = new BooleanQuery(); query.add(query1, Occur.SHOULD); query.add(query2, Occur.SHOULD); isearcher = new IndexSearcher(directory, true); TopDocs ts = isearcher.search(query, null, 100);

3) MultiFieldQueryParser: 多Field中查询。

  1. QueryParserparser= new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{ "path" , "contents" },analyzer);
  2. Queryquery=parser.parse(keyword);
  3. isearcher=new IndexSearcher(FSDirectory.open(indexDir), true );
  4. TopDocsts=isearcher.search(query,null , 100 );
  1. QueryParserparser=newMultiFieldQueryParser(Version.LUCENE_CURRENT,newString[]{"path","contents"},analyzer);
  2. Queryquery=parser.parse(keyword);
  3. isearcher=newIndexSearcher(FSDirectory.open(indexDir),true);
  4. TopDocsts=isearcher.search(query,null,100);

QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{"path", "contents"}, analyzer); Query query = parser.parse(keyword); isearcher = new IndexSearcher(FSDirectory.open(indexDir), true); TopDocs ts = isearcher.search(query, null, 100);

10. 高亮器Highlighter:在网页中对搜索结果予以高亮显示。
1) 在classpath添加contrib/highlighter/lucene-highlighter-2.9.1.jar
2) 示例伪代码

  1. SimpleHTMLFormattershf= new SimpleHTMLFormatter( "<spanstyle=" color:red "mce_style=" color:red ">" , "</span>" ); //默认是<b>..</b>
  2. //构造高亮器:指定高亮的格式,指定查询计分器
  3. Highlighterhighlighter=new Highlighter(shf, new QueryScorer(query));
  4. //设置块划分器
  5. highlighter.setTextFragmenter(new SimpleFragmenter(Integer.MAX_VALUE));
  6. Stringcontent=highlighter.getBestFragment(Analyzer,"fieldName" , "fieldValue" );
  1. SimpleHTMLFormattershf=newSimpleHTMLFormatter("<span
  2. style="color:red"mce_style="color:red">","</span>");
  3. //默认是<b>..</b>//构造高亮器:指定高亮的格式,指定查询计分器Highlighter
  4. highlighter=newHighlighter(shf,newQueryScorer(query));//设置块划分器
  5. highlighter.setTextFragmenter(newSimpleFragmenter(Integer.MAX_VALUE));
  6. Stringcontent=highlighter.getBestFragment(Analyzer,"fieldName",
  7. "fieldValue");

SimpleHTMLFormatter shf = new SimpleHTMLFormatter("<span style="color:red" mce_style="color:red">", "</span>"); //默认是<b>..</b> // 构造高亮器:指定高亮的格式,指定查询计分器 Highlighter highlighter = new Highlighter(shf, new QueryScorer(query)); //设置块划分器 highlighter.setTextFragmenter(new SimpleFragmenter(Integer.MAX_VALUE)); String content = highlighter.getBestFragment(Analyzer, "fieldName", "fieldValue");

11. 优化
1) 使用IndexWriter须注意
修改索引后,需flush()或close()方能生效
非线程安全,任一时刻仅能有一个线程对其操作.
2) 使用IndexSearcher须注意
一旦打开,不会搜索到以后添加的索引
线程安全,多个线程仅需一个实例
3) 最佳实践
多个线程共享一个IndexSearcher, 只有当索引修改后才重新打开IndexSearcher
多个线程共享一个IndexWriter并严格同步
异步修改索引提高性能(JMS)
为每个Document创建单独的索引目录

12. 在emall项目中整合Lucene对产品的ID,名称和描述进行全文搜索。

13. 使用Compass简化Lucene操作。(未完待续)

Lucene2.9.1使用小结 (注释1)相关推荐

  1. C++ 注释风格建议

    文章目录 0.前言 1.注释风格(Comment Style) 2.文件注释(File Comments) 3.类注释(Class Comments) 4.函数注释(Function Comments ...

  2. c语言深度剖析(12)—注释符号

    1. 似是而非的问题 下面的注释是正确的吗? #include<stdio.h>int main() {int/**/i; //合法int i;char* s = "abcdef ...

  3. 程序员常见的坏习惯,你躺枪了吗?

    作为一名程序员,犯错误是不可避免的. 不过呢,有些坏习惯会妨碍你成为一名优秀的程序员. 1.寻找借口 编程出现bug是很正常的,一些程序员会"机智"地为自己甩锅: A.这不是我干的 ...

  4. 如何阅读英文原版教材

    读原版书的三个误区 1.觉得自己词汇量不够. 事实上, 这个是最大的误区. 我可以随手写下几个单词, 你是否知道它们的意思?antihistamine? placebo? 好吧, 基本上大多数人不会知 ...

  5. 持续更新!福昕阅读器那些超好用的隐藏功能

    「福昕阅读器 专业版」是新功能首发版本,不仅可以阅读批注PDF文档,还支持划词翻译.PDF云文档等,但还有一些超级好用的功能,很多老用户都不知道哦~ 今天,我们就来跟大家揭秘这些好用的隐藏功能. 下载 ...

  6. 被误认为是外国人开发的4款软件,功能强大到离谱,且用且珍惜

    国外的月亮不一定比国内圆,随着国内互联网飞速发展,国内研发出许多实用又良心的软件,由于偏见,功能强大的它们却被误认为是外国佬研发的. 1.Foxit PDF用系统自带的Adobe实在难用,Foxit这 ...

  7. EJB3.0 注释小结

    EJB3 就靠注释吃饭了,总结一下以备后查. @Id 显示声明属性为标识符 @GeneratedValue(strategy=GenerationType.IDENTITY) 表示主键是自动生成策略, ...

  8. [Swagger2]分组和接口注释及小结

    分组和接口注释及小结 配置API分组 1.如果没有配置分组,默认是default.通过groupName()方法即可配置分组: @Bean public Docket docket(Environme ...

  9. php脚本开头注释_PHP文件注释标记及规范小结

    PHP文件注释标记及规范小结 发布时间:2016-06-17 来源: 点击: 次 PHP 注释标记 @access 使用范围:class,function,var,define,module 该标记用 ...

最新文章

  1. vue样式 引入图片_详解Vue.js中引入图片路径的几种方式
  2. 学好Linux必备知识
  3. Python 代码性能优化技巧
  4. 你值得拥有:25个Linux性能监控工具
  5. bazel编译tensorflow 生成libtensorflow_inference.so 和 libandroid_tensorflow_inference_java.jar
  6. C语言 | C语言实现日历打印
  7. Win32字符串处理函数
  8. query什么意思php,关于 QueryPHP
  9. Android System分区大小异常
  10. VScode Remote 远程开发与调试(转)
  11. android 呼吸灯权限_小米新机搭载炫彩呼吸灯酷到爆;三星顶级旗舰Note 10正式官宣...
  12. Mysql学习总结(43)——MySQL主从复制详细配置
  13. 大数据之-Hadoop3.x_MapReduce_切片源码分析---大数据之hadoop3.x工作笔记0104
  14. wcf 接收post数据_简单聊下HTTP中POST和GET请求本质区别
  15. 阿里云CentOs 6.4 yum报错Couldn't resolve host'xx
  16. oracle 认证视频,Oracle 认证专家视频教程-OCP全套教程【98集】_IT教程网
  17. Latex:表格插入图片
  18. [鼠标指针][仅需1步]宝藏的猫咪Cat老师[win10/11][点击看更多免费]......
  19. bootstrap按钮组btn-group
  20. 硬件设计2---什么是电阻?

热门文章

  1. 【最新可用】Oracle官网下载Oracle 11g XE
  2. 对学校的希望和寄语_新学期对学校的寄语
  3. 点与有向线段的位置关系
  4. [转]Golang中goroutine的调度器详解
  5. dann的alpha torch_pytorch BiLSTM+CRF代码详解
  6. 我的AI之路(54)--使用Pytorch内置的动作识别模型
  7. Oracle GoldenGate 文章集合
  8. Markdown - Emoji表情大全
  9. DCC:Deep continuous clustering
  10. Metasploit技术(一)——Metasploit简介与基础