一、搜索流程详解

1. 先看一下Lucene的架构图

由图可知搜索的过程如下:

  用户输入搜索的关键字、对关键字进行分词、根据分词结果去索引库里面找到对应的文章id、根据文章id找到对应的文章

2. Lucene搜索API 图示

3. Lucene搜索代码示例

先在pom.xml里面引入查询分析器模块

  1. <!-- lucene-queryparser 查询分析器模块 -->
  2. <dependency>
  3. <groupId>org.apache.lucene</groupId>
  4. <artifactId>lucene-queryparser</artifactId>
  5. <version>7.3.0</version>
  6. </dependency>
  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5. import java.text.ParseException;
  6.  
  7. import org.apache.lucene.analysis.Analyzer;
  8. import org.apache.lucene.document.Document;
  9. import org.apache.lucene.index.DirectoryReader;
  10. import org.apache.lucene.index.IndexReader;
  11. import org.apache.lucene.queryparser.classic.QueryParser;
  12. import org.apache.lucene.search.IndexSearcher;
  13. import org.apache.lucene.search.Query;
  14. import org.apache.lucene.search.ScoreDoc;
  15. import org.apache.lucene.search.TopDocs;
  16. import org.apache.lucene.store.Directory;
  17. import org.apache.lucene.store.FSDirectory;
  18.  
  19. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  20.  
  21. /**
  22. * @Description: lucene 搜索基本流程示例
  23. * @author liguangsheng
  24. * @date 2018年5月11日
  25. *
  26. */
  27.  
  28. public class SearchBaseFlow {
  29.  
  30. public static void main(String[] args)
  31. throws IOException, ParseException, org.apache.lucene.queryparser.classic.ParseException {
  32. // 使用的分词器
  33. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  34. // 索引存储目录
  35. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  36. // 索引读取器
  37. IndexReader indexReader = DirectoryReader.open(directory);
  38. // 索引搜索器
  39. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  40. // 要搜索的字段
  41. String filedName = "name";
  42. // 查询生成器(解析输入生成Query查询对象)
  43. QueryParser parser = new QueryParser(filedName, analyzer);
  44. // 通过parse解析输入(分词),生成query对象
  45. Query query = parser.parse("Thinkpad");
  46. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  47. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  48.  
  49. // 获得总命中数
  50. System.out.println(topDocs.totalHits);
  51. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  52. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  53. // 根据文档id取存储的文档
  54. Document hitDoc = indexSearcher.doc(sdoc.doc);
  55. // 取文档的字段
  56. System.out.println(hitDoc.get(filedName));
  57. }
  58.  
  59. // 使用完毕,关闭、释放资源
  60. indexReader.close();
  61. directory.close();
  62. }
  63. }

示例代码的图解:

二、搜索核心API详解

1. IndexReader  索引读取器

Open一个读取器,读取的是该时刻点的索引视图。如果后续索引发生改变,需重新open一个读取器。获得索引读取器的方式:

DirectoryReader.open(IndexWriter indexWriter) 优先使用

DirectoryReader.open(Directory)

DirectoryReader.openIfChanged(DirectoryReader) 共享当前reader资源重新打开一个(当索引变化时)

IndexReader分为两类:

复合读取器,多个读取器的复合。只可直接用它获取stored fields 。在内部通过CompositeReader.getSequentialSubReaders 得到里面的叶子读取器来获取其他数据

叶子读取器:支持获取stored fields, doc values, terms(词项), and postings (词项对应的文档)

DirectoryReader 是 复合读取器

IndexReader 主要API

LeafReader 主要API:

2.  IndexSearcher 索引搜索器

应用通过调用它的search(Query,int)重载方法在一个IndexReader上实现搜索。出于性能的考虑,请使用一个IndexSearcher实例,除非索引发生变化。如索引更新了则通过DirectoryReader.openIfChanged(DirectoryReader)  取得新的读取器,再创建新的搜索器。

 IndexSearcher  索引搜索器   API

搜索 API:

获取文档 API:

TopDocs 搜索命中的结果集 (Top-N)

TopFieldDocs 按字段排序的搜索命中结果集

ScoreDoc

三、基本查询详解

Query  查询的表示,它的可实例化子类有

要掌握的基本查询

1、TermQuery  词项查询

  最基本、最常用的查询。用来查询指定字段包含指定词项的文档。

  TermQuery tq = new TermQuery(new Term(“name", “thinkpad"));

2、BooleanQuery  布尔查询

  搜索的条件往往是多个的,如要查询名称包含“电脑” 或 “thinkpad”的商品,就需要两个词项查询做或合并。布尔查询就是用来组合多个子查询的。每个子查询称为布尔字句 BooleanClause,布尔字句自身也可以是组合的。 组合关系支持如下四种:

Occur.SHOULD 或

Occur.MUST 且

Occur.MUST_NOT 且非

Occur.FILTER 同 MUST,但该字句不参与评分

布尔查询默认的最大字句数为1024,在将通配符查询这样的查询rewriter为布尔查询时,往往会产生很多的字句,可能抛出TooManyClauses 异常。可通过BooleanQuery.setMaxClauseCount(int)设置最大字句数。

  1. // 布尔查询
  2. Query query1 = new TermQuery(new Term(filedName, "thinkpad"));
  3. Query query2 = new TermQuery(new Term("simpleIntro", "英特尔"));
  4. BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
  5. booleanQueryBuilder.add(query1, Occur.SHOULD);
  6. booleanQueryBuilder.add(query2, Occur.MUST);
  7. BooleanQuery booleanQuery = booleanQueryBuilder.build();
  8.  
  9. // 可像下一行这样写
  10. // BooleanQuery booleanQuery = new BooleanQuery.Builder()
  11. // .add(query1, Occur.SHOULD).add(query2, Occur.MUST).build();

3、PhraseQuery  短语查询

  最常用的查询,匹配特定序列的多个词项。PhraserQuery使用一个位置移动因子(slop)来决定任意两个词项的位置可最大移动多少个位置来进行匹配,默认为0。有两种方式来构建对象:

注意:所有加入的词项都匹配才算匹配(即使是你在同一位置加入多个词项)。如果需要在同一位置匹配多个同义词中的一个,适合用MultiPhraseQuery

  1. PhraseQuery phraseQuery1 = new PhraseQuery("name", "thinkpad",
  2. "carbon");
  3.  
  4. PhraseQuery phraseQuery2 = new PhraseQuery(1, "name", "thinkpad",
  5. "carbon");
  6.  
  7. PhraseQuery phraseQuery3 = new PhraseQuery("name", "笔记本电脑", "联想");
  8.  
  9. PhraseQuery phraseQuery4 = new PhraseQuery.Builder()
  10. .add(new Term("name", "笔记本电脑"), 4)
  11. .add(new Term("name", "联想"), 5).build();
  12. // 这两句等同
  13. PhraseQuery phraseQuery5 = new PhraseQuery.Builder()
  14. .add(new Term("name", "笔记本电脑"), 0)
  15. .add(new Term("name", "联想"), 1).build();

PhraseQuery  slop  移动因子说明:

String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超极本轻薄笔记本电脑联想";

A、如果想用  “thinkpad  carbon” 来匹配 name。因中间有 x1,则需要将thinkpad 向右移动1个位置。

B、如果想用  “carbon  thinkpad” 来匹配 name。因中间有 x1,则需要将carbon 向右移动3个位置。

  1. // String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超极本轻薄笔记本电脑联想";
  2.  
  3. // PhraseQuery 短语查询
  4. PhraseQuery phraseQuery2 = new PhraseQuery(1, "name", "thinkpad","carbon");
  5. // slop示例
  6. PhraseQuery phraseQuery2Slop = new PhraseQuery(3, "name", "carbon", "thinkpad");
  7. PhraseQuery phraseQuery3 = new PhraseQuery("name", "笔记本电脑", "联想");
  8. // slop示例
  9. PhraseQuery phraseQuery3Slop = new PhraseQuery(2, "name", "联想","笔记本电脑");

4、MultiPhraseQuery 多重短语查询

短语查询的一种更通用的用法,支持同位置多个词的OR匹配。通过里面的Builder来构建MultiPhraseQuery:

  1. // 4 MultiPhraseQuery 多重短语查询
  2. Term[] terms = new Term[2];
  3. terms[0] = new Term("name", "笔记本");
  4. terms[1] = new Term("name", "笔记本电脑");
  5. Term t = new Term("name", "联想");
  6. MultiPhraseQuery multiPhraseQuery = new MultiPhraseQuery.Builder()
  7. .add(terms).add(t).build();
  8.  
  9. // 对比 PhraseQuery在同位置加入多个词 ,同位置的多个词都需匹配,所以查不出。
  10. PhraseQuery pquery = new PhraseQuery.Builder().add(terms[0], 0)
  11. .add(terms[1], 0).add(t, 1).build();

前面4个查询的完整示例代码:

  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5.  
  6. import org.apache.lucene.analysis.Analyzer;
  7. import org.apache.lucene.document.Document;
  8. import org.apache.lucene.index.DirectoryReader;
  9. import org.apache.lucene.index.IndexReader;
  10. import org.apache.lucene.index.Term;
  11. import org.apache.lucene.queryparser.classic.ParseException;
  12. import org.apache.lucene.search.BooleanClause.Occur;
  13. import org.apache.lucene.search.BooleanQuery;
  14. import org.apache.lucene.search.IndexSearcher;
  15. import org.apache.lucene.search.MultiPhraseQuery;
  16. import org.apache.lucene.search.PhraseQuery;
  17. import org.apache.lucene.search.Query;
  18. import org.apache.lucene.search.ScoreDoc;
  19. import org.apache.lucene.search.TermQuery;
  20. import org.apache.lucene.search.TopDocs;
  21. import org.apache.lucene.store.Directory;
  22. import org.apache.lucene.store.FSDirectory;
  23.  
  24. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  25.  
  26. /**
  27. * @Description: 搜索查询示例
  28. * @author liguangsheng
  29. * @date 2018年5月12日
  30. *
  31. */
  32.  
  33. public class SearchQueryDemo {
  34.  
  35. public static void main(String[] args) throws IOException, ParseException {
  36. // 使用的分词器
  37. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  38. // 索引存储目录
  39. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  40. // 索引读取器
  41. IndexReader indexReader = DirectoryReader.open(directory);
  42. // 索引搜索器
  43. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  44. // 要搜索的字段
  45. String filedName = "name";
  46.  
  47. // 1、词项查询
  48. Query query1 = new TermQuery(new Term(filedName, "thinkpad"));
  49. System.out.println("************** 词项查询 ******************");
  50. doSearch(query1, indexSearcher);
  51.  
  52. // 2、布尔查询
  53. Query query2 = new TermQuery(new Term("simpleIntro", "英特尔"));
  54. BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
  55. booleanQueryBuilder.add(query1, Occur.SHOULD);
  56. booleanQueryBuilder.add(query2, Occur.MUST);
  57. BooleanQuery booleanQuery = booleanQueryBuilder.build();
  58.  
  59. // 可像下一行这样写
  60. // BooleanQuery booleanQuery = new BooleanQuery.Builder()
  61. // .add(query1, Occur.SHOULD).add(query2, Occur.MUST).build();
  62.  
  63. System.out.println("************** 布尔查询 ******************");
  64. doSearch(booleanQuery, indexSearcher);
  65.  
  66. // 3、PhraseQuery 短语查询
  67. // String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超极本轻薄笔记本电脑联想";
  68. PhraseQuery phraseQuery1 = new PhraseQuery("name", "thinkpad", "carbon");
  69. System.out.println("************** phrase 短语查询 ******************");
  70. doSearch(phraseQuery1, indexSearcher);
  71.  
  72. PhraseQuery phraseQuery2 = new PhraseQuery(1, "name", "thinkpad", "carbon");
  73. System.out.println("************** phrase 短语查询 ******************");
  74. doSearch(phraseQuery2, indexSearcher);
  75.  
  76. // slop示例 3表示最大可以移动的位置,移动的过程中只要匹配短语carbon thinkpad即可
  77. PhraseQuery phraseQuery2Slop = new PhraseQuery(3, "name", "carbon", "thinkpad");
  78. System.out.println("********** phrase slop 短语查询 ***************");
  79. doSearch(phraseQuery2Slop, indexSearcher);
  80.  
  81. PhraseQuery phraseQuery3 = new PhraseQuery("name", "笔记本电脑", "联想");
  82. System.out.println("************** phrase 短语查询 ******************");
  83. doSearch(phraseQuery3, indexSearcher);
  84.  
  85. // slop示例
  86. PhraseQuery phraseQuery3Slop = new PhraseQuery(2, "name", "联想", "笔记本电脑");
  87. System.out.println("************** phrase s 短语查询 ******************");
  88. doSearch(phraseQuery3Slop, indexSearcher);
  89.  
  90. PhraseQuery phraseQuery4 = new PhraseQuery.Builder().add(new Term("name", "笔记本电脑"), 4) // 4、5是这个词的位置,和 0、1等同
  91. .add(new Term("name", "联想"), 5).build();
  92. System.out.println("********** phrase Builder 1 短语查询 **************");
  93. doSearch(phraseQuery4, indexSearcher);
  94.  
  95. // 等同 phraseQuery4
  96. PhraseQuery phraseQuery5 = new PhraseQuery.Builder().add(new Term("name", "笔记本电脑"), 0) // 4、5是这个词的位置,和 0、1等同
  97. .add(new Term("name", "联想"), 1).build();
  98. System.out.println("*********** phrase Builder 2 短语查询 ***********");
  99. doSearch(phraseQuery5, indexSearcher);
  100.  
  101. // 4 MultiPhraseQuery 多重短语查询
  102. Term[] terms = new Term[2];
  103. terms[0] = new Term("name", "笔记本");
  104. terms[1] = new Term("name", "笔记本电脑");
  105. Term t = new Term("name", "联想");
  106. MultiPhraseQuery multiPhraseQuery = new MultiPhraseQuery.Builder().add(terms).add(t).build();
  107. System.out.println("************** multiPhraseQuery 短语查询 ******************");
  108. doSearch(multiPhraseQuery, indexSearcher);
  109.  
  110. // 对比 PhraseQuery在同位置加入多个词 ,同位置的多个词都需匹配,所以查不出。
  111. PhraseQuery pquery = new PhraseQuery.Builder().add(terms[0], 0).add(terms[1], 0).add(t, 1).build();
  112. System.out.println("************** multiPhraseQuery 对比 PhraseQuery 短语查询 ******************");
  113. doSearch(pquery, indexSearcher);
  114.  
  115. // 使用完毕,关闭、释放资源
  116. indexReader.close();
  117. directory.close();
  118. }
  119.  
  120. private static void doSearch(Query query, IndexSearcher indexSearcher) throws IOException {
  121. // 打印输出查询
  122. System.out.println("query: " + query.toString());
  123.  
  124. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  125. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  126.  
  127. System.out.println("**** 查询结果 ");
  128. // 获得总命中数
  129. System.out.println("总命中数:" + topDocs.totalHits);
  130. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  131. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  132. // 根据文档id取存储的文档
  133. Document hitDoc = indexSearcher.doc(sdoc.doc);
  134. System.out.println("-------------- docId=" + sdoc.doc + ",score=" + sdoc.score);
  135. // 取文档的字段
  136. System.out.println("prodId:" + hitDoc.get("prodId"));
  137. System.out.println("name:" + hitDoc.get("name"));
  138. System.out.println("simpleIntro:" + hitDoc.get("simpleIntro"));
  139. System.out.println("price:" + hitDoc.get("price"));
  140.  
  141. System.out.println();
  142. }
  143.  
  144. }
  145. }

5、SpanNearQuery  临近查询(跨度查询)

用于更复杂的短语查询,可以指定词间位置的最大间隔跨度。通过组合一系列的SpanQuery 实例来进行查询,可以指定是否按顺序匹配、slop、gap。

  1. // SpanNearQuery 临近查询
  2. SpanTermQuery tq1 = new SpanTermQuery(new Term("name", "thinkpad"));
  3. SpanTermQuery tq2 = new SpanTermQuery(new Term("name", "carbon"));
  4. SpanNearQuery spanNearQuery = new SpanNearQuery(
  5. new SpanQuery[] { tq1, tq2 }, 1, true);
  6.  
  7. // SpanNearQuery 临近查询 gap slop 使用
  8. SpanNearQuery.Builder spanNearQueryBuilder = SpanNearQuery
  9. .newOrderedNearQuery("name");
  10. spanNearQueryBuilder.addClause(tq1).addGap(0).setSlop(1)
  11. .addClause(tq2);
  12. SpanNearQuery spanNearQuery5 = spanNearQueryBuilder.build();

完整代码示例

  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5.  
  6. import org.apache.lucene.analysis.Analyzer;
  7. import org.apache.lucene.document.Document;
  8. import org.apache.lucene.index.DirectoryReader;
  9. import org.apache.lucene.index.IndexReader;
  10. import org.apache.lucene.index.Term;
  11. import org.apache.lucene.queryparser.classic.ParseException;
  12. import org.apache.lucene.search.IndexSearcher;
  13. import org.apache.lucene.search.Query;
  14. import org.apache.lucene.search.ScoreDoc;
  15. import org.apache.lucene.search.TopDocs;
  16. import org.apache.lucene.search.spans.SpanNearQuery;
  17. import org.apache.lucene.search.spans.SpanQuery;
  18. import org.apache.lucene.search.spans.SpanTermQuery;
  19. import org.apache.lucene.store.Directory;
  20. import org.apache.lucene.store.FSDirectory;
  21.  
  22. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  23.  
  24. /**
  25. * @Description: SpanNearQuery 临近查询(跨度查询)
  26. * @author liguangsheng
  27. * @date 2018年5月12日
  28. *
  29. */
  30. public class SpanNearQueryDemo {
  31.  
  32. public static void main(String[] args) throws IOException, ParseException {
  33. // 使用的分词器
  34. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  35. // 索引存储目录
  36. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  37. // 索引读取器
  38. IndexReader indexReader = DirectoryReader.open(directory);
  39. // 索引搜索器
  40. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  41.  
  42. // String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超极本轻薄笔记本电脑联想";
  43.  
  44. // SpanNearQuery 临近查询
  45. SpanTermQuery tq1 = new SpanTermQuery(new Term("name", "thinkpad"));
  46. SpanTermQuery tq2 = new SpanTermQuery(new Term("name", "carbon"));
  47. SpanNearQuery spanNearQuery = new SpanNearQuery(
  48. new SpanQuery[] { tq1, tq2 }, 1, true);
  49.  
  50. System.out.println("************** SpanNearQuery 临近查询 ************");
  51. doSearch(spanNearQuery, indexSearcher);
  52.  
  53. // 下面的例子词是反序的
  54. SpanNearQuery spanNearQuery2 = new SpanNearQuery(
  55. new SpanQuery[] { tq2, tq1 }, 1, true);
  56.  
  57. System.out.println(
  58. "************** SpanNearQuery 临近查询 2 1,true************");
  59. doSearch(spanNearQuery2, indexSearcher);
  60.  
  61. SpanNearQuery spanNearQuery3 = new SpanNearQuery(
  62. new SpanQuery[] { tq2, tq1 }, 3, true);
  63.  
  64. System.out.println(
  65. "************** SpanNearQuery 临近查询 3 3, true************");
  66. doSearch(spanNearQuery3, indexSearcher);
  67.  
  68. SpanNearQuery spanNearQuery4 = new SpanNearQuery(
  69. new SpanQuery[] { tq2, tq1 }, 3, false);
  70.  
  71. System.out.println(
  72. "************** SpanNearQuery 临近查询 4 3, false************");
  73. doSearch(spanNearQuery4, indexSearcher);
  74.  
  75. // SpanNearQuery 临近查询 gap slop 使用 1
  76. SpanTermQuery ctq1 = new SpanTermQuery(new Term("name", "张三"));
  77. SpanTermQuery ctq2 = new SpanTermQuery(new Term("name", "在理"));
  78. SpanNearQuery.Builder spanNearQueryBuilder = SpanNearQuery
  79. .newOrderedNearQuery("name");
  80. spanNearQueryBuilder.addClause(ctq1).addGap(0).setSlop(2)
  81. .addClause(ctq2);
  82.  
  83. System.out.println("************** SpanNearQuery 临近查询 ************");
  84. doSearch(spanNearQueryBuilder.build(), indexSearcher);
  85.  
  86. // SpanNearQuery 临近查询 gap slop 使用 2
  87. SpanNearQuery.Builder spanNearQueryBuilder2 = SpanNearQuery
  88. .newOrderedNearQuery("name");
  89. spanNearQueryBuilder2.addClause(ctq1).addGap(2).setSlop(0)
  90. .addClause(ctq2);
  91.  
  92. System.out.println("************** SpanNearQuery 临近查询 ************");
  93. doSearch(spanNearQueryBuilder2.build(), indexSearcher);
  94.  
  95. // SpanNearQuery 临近查询 gap slop 使用 3
  96. SpanNearQuery.Builder spanNearQueryBuilder3 = SpanNearQuery
  97. .newOrderedNearQuery("name");
  98. spanNearQueryBuilder3.addClause(ctq1).addGap(1).setSlop(1)
  99. .addClause(ctq2);
  100.  
  101. System.out.println("************** SpanNearQuery 临近查询 ************");
  102. doSearch(spanNearQueryBuilder3.build(), indexSearcher);
  103.  
  104. // 使用完毕,关闭、释放资源
  105. indexReader.close();
  106. directory.close();
  107. }
  108.  
  109. private static void doSearch(Query query, IndexSearcher indexSearcher)
  110. throws IOException {
  111. // 打印输出查询
  112. System.out.println("query: " + query.toString());
  113.  
  114. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  115. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  116.  
  117. System.out.println("**** 查询结果 ");
  118. // 获得总命中数
  119. System.out.println("总命中数:" + topDocs.totalHits);
  120. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  121. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  122. // 根据文档id取存储的文档
  123. Document hitDoc = indexSearcher.doc(sdoc.doc);
  124. System.out.println("-------------- docId=" + sdoc.doc + ",score="
  125. + sdoc.score);
  126. // 取文档的字段
  127. System.out.println("prodId:" + hitDoc.get("prodId"));
  128. System.out.println("name:" + hitDoc.get("name"));
  129. System.out.println("simpleIntro:" + hitDoc.get("simpleIntro"));
  130. System.out.println("price:" + hitDoc.get("price"));
  131.  
  132. System.out.println();
  133. }
  134.  
  135. }
  136. }

6、TermRangeQuery 词项范围查询

用于查询包含某个范围内的词项的文档,如以字母开头a到c的词项。词项在反向索引中是排序的,只需指定的开始词项、结束词项,就可以查询该范围的词项。 如果是做数值的范围查询则用 PointRangeQuery 。

参数说明:

第1个参数:要查询的字段-field

第2个参数::下边界词-lowerTerm

第3个参数:上边界词-upperTerm

第4个参数:是否包含下边界-includeLower

第5个参数:是否包含上边界 includeUpper

  1. // TermRangeQuery 词项范围查询
  2. TermRangeQuery termRangeQuery = TermRangeQuery.newStringRange("name",
  3. "carbon", "张三", false, true);

完整示例代码

  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5.  
  6. import org.apache.lucene.analysis.Analyzer;
  7. import org.apache.lucene.document.Document;
  8. import org.apache.lucene.index.DirectoryReader;
  9. import org.apache.lucene.index.IndexReader;
  10. import org.apache.lucene.queryparser.classic.ParseException;
  11. import org.apache.lucene.search.IndexSearcher;
  12. import org.apache.lucene.search.Query;
  13. import org.apache.lucene.search.ScoreDoc;
  14. import org.apache.lucene.search.TermRangeQuery;
  15. import org.apache.lucene.search.TopDocs;
  16. import org.apache.lucene.store.Directory;
  17. import org.apache.lucene.store.FSDirectory;
  18.  
  19. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  20.  
  21. /**
  22. * @Description: TermRangeQuery 词项范围查询
  23. * @author liguangsheng
  24. * @date 2018年5月12日
  25. *
  26. */
  27. public class TermRangeQueryDemo {
  28.  
  29. /**
  30. * lucene 搜索查询示例
  31. */
  32. public static void main(String[] args) throws IOException, ParseException {
  33. // 使用的分词器
  34. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  35. // 索引存储目录
  36. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  37. // 索引读取器
  38. IndexReader indexReader = DirectoryReader.open(directory);
  39. // 索引搜索器
  40. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  41.  
  42. // String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超极本轻薄笔记本电脑联想";
  43.  
  44. // TermRangeQuery 词项范围查询
  45. TermRangeQuery termRangeQuery = TermRangeQuery.newStringRange("name",
  46. "carbon", "张三", false, true);
  47.  
  48. System.out.println("********** TermRangeQuery 词项范围查询 ***********");
  49. doSearch(termRangeQuery, indexSearcher);
  50.  
  51. // 使用完毕,关闭、释放资源
  52. indexReader.close();
  53. directory.close();
  54. }
  55.  
  56. private static void doSearch(Query query, IndexSearcher indexSearcher)
  57. throws IOException {
  58. // 打印输出查询
  59. System.out.println("query: " + query.toString());
  60.  
  61. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  62. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  63.  
  64. System.out.println("**** 查询结果 ");
  65. // 获得总命中数
  66. System.out.println("总命中数:" + topDocs.totalHits);
  67. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  68. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  69. // 根据文档id取存储的文档
  70. Document hitDoc = indexSearcher.doc(sdoc.doc);
  71. System.out.println("-------------- docId=" + sdoc.doc + ",score="
  72. + sdoc.score);
  73. // 取文档的字段
  74. System.out.println("prodId:" + hitDoc.get("prodId"));
  75. System.out.println("name:" + hitDoc.get("name"));
  76. System.out.println("simpleIntro:" + hitDoc.get("simpleIntro"));
  77. System.out.println("price:" + hitDoc.get("price"));
  78.  
  79. System.out.println();
  80. }
  81.  
  82. }
  83. }

7、PrefixQuery, WildcardQuery, RegexpQuery

PrefixQuery:前缀查询,查询包含以xxx为前缀的词项的文档,是通配符查询,如 app,实际是 app*

  1. // PrefixQuery 前缀查询
  2. PrefixQuery prefixQuery = new PrefixQuery(new Term("name", "think"));

WildcardQuery:通配符查询, *表示0个或多个字符,?表示1个字符,\是转义符。通配符查询可能会比较慢,不可以通配符开头(那样就是所有词项了)

  1. // WildcardQuery 通配符查询
  2. WildcardQuery wildcardQuery = new WildcardQuery(
  3. new Term("name", "think*"));

RegexpQuery:正则表达式查询,词项符合某正则表达式

  1. // RegexpQuery 正则表达式查询
  2. RegexpQuery regexpQuery = new RegexpQuery(new Term("name", "厉害.{4}"));

注意:这三种查询可能会比较慢,使用时谨慎

8、FuzzyQuery 模糊查询

简单地与索引词项进行相近匹配,允许最大2个不同字符。常用于拼写错误的容错:如把 “thinkpad” 拼成 “thinkppd”或 “thinkd”,使用FuzzyQuery 仍可搜索到正确的结果。

  1. // FuzzyQuery 模糊查询
  2. FuzzyQuery fuzzyQuery = new FuzzyQuery(new Term("name", "thind"));
  3.  
  4. FuzzyQuery fuzzyQuery2 = new FuzzyQuery(new Term("name", "thinkd"), 2);
  5.  
  6. FuzzyQuery fuzzyQuery3 = new FuzzyQuery(new Term("name", "thinkpaddd"));
  7.  
  8. FuzzyQuery fuzzyQuery4 = new FuzzyQuery(new Term("name", "thinkdaddd"));

7和8对应查询的完整示例代码

  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5.  
  6. import org.apache.lucene.analysis.Analyzer;
  7. import org.apache.lucene.document.Document;
  8. import org.apache.lucene.index.DirectoryReader;
  9. import org.apache.lucene.index.IndexReader;
  10. import org.apache.lucene.index.Term;
  11. import org.apache.lucene.queryparser.classic.ParseException;
  12. import org.apache.lucene.search.FuzzyQuery;
  13. import org.apache.lucene.search.IndexSearcher;
  14. import org.apache.lucene.search.PrefixQuery;
  15. import org.apache.lucene.search.Query;
  16. import org.apache.lucene.search.RegexpQuery;
  17. import org.apache.lucene.search.ScoreDoc;
  18. import org.apache.lucene.search.TopDocs;
  19. import org.apache.lucene.search.WildcardQuery;
  20. import org.apache.lucene.store.Directory;
  21. import org.apache.lucene.store.FSDirectory;
  22.  
  23. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  24.  
  25. /**
  26. * @Description: PrefixQuery前缀查询/WildcardQuery通配符查询/RegexpQuery正则表达式查询/FuzzyQuery模糊查询
  27. * @author liguangsheng
  28. * @date 2018年5月12日
  29. *
  30. */
  31. public class PrefixWildcardRegexpFuzzyQueryDemo {
  32.  
  33. public static void main(String[] args) throws IOException, ParseException {
  34. // 使用的分词器
  35. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  36. // 索引存储目录
  37. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  38. // 索引读取器
  39. IndexReader indexReader = DirectoryReader.open(directory);
  40. // 索引搜索器
  41. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  42.  
  43. // String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超极本轻薄笔记本电脑联想";
  44.  
  45. // PrefixQuery 前缀查询
  46. PrefixQuery prefixQuery = new PrefixQuery(new Term("name", "think"));
  47. System.out.println("********** PrefixQuery 前缀查询 ***********");
  48. doSearch(prefixQuery, indexSearcher);
  49.  
  50. // WildcardQuery 通配符查询
  51. WildcardQuery wildcardQuery = new WildcardQuery(
  52. new Term("name", "think*"));
  53.  
  54. System.out.println("********** WildcardQuery 通配符 ***********");
  55. doSearch(wildcardQuery, indexSearcher);
  56.  
  57. // WildcardQuery 通配符查询
  58. WildcardQuery wildcardQuery2 = new WildcardQuery(
  59. new Term("name", "厉害了???"));
  60. System.out.println("********** WildcardQuery 通配符 ***********");
  61. doSearch(wildcardQuery2, indexSearcher);
  62.  
  63. // RegexpQuery 正则表达式查询
  64. RegexpQuery regexpQuery = new RegexpQuery(new Term("name", "厉害.{4}"));
  65. System.out.println("**********RegexpQuery 正则表达式查询***********");
  66. doSearch(regexpQuery, indexSearcher);
  67.  
  68. // FuzzyQuery 模糊查询
  69. FuzzyQuery fuzzyQuery = new FuzzyQuery(new Term("name", "thind"));
  70. System.out.println("**********FuzzyQuery 模糊查询***********");
  71. doSearch(fuzzyQuery, indexSearcher);
  72.  
  73. // FuzzyQuery 模糊查询
  74. FuzzyQuery fuzzyQuery2 = new FuzzyQuery(new Term("name", "thinkd"), 2);
  75. System.out.println("**********FuzzyQuery 模糊查询***********");
  76. doSearch(fuzzyQuery2, indexSearcher);
  77.  
  78. // FuzzyQuery 模糊查询
  79. FuzzyQuery fuzzyQuery3 = new FuzzyQuery(new Term("name", "thinkpaddd"));
  80. System.out.println("**********FuzzyQuery 模糊查询***********");
  81. doSearch(fuzzyQuery3, indexSearcher);
  82.  
  83. // FuzzyQuery 模糊查询
  84. FuzzyQuery fuzzyQuery4 = new FuzzyQuery(new Term("name", "thinkdaddd"));
  85. System.out.println("**********FuzzyQuery 模糊查询***********");
  86. doSearch(fuzzyQuery4, indexSearcher);
  87.  
  88. // 使用完毕,关闭、释放资源
  89. indexReader.close();
  90. directory.close();
  91. }
  92.  
  93. private static void doSearch(Query query, IndexSearcher indexSearcher)
  94. throws IOException {
  95. // 打印输出查询
  96. System.out.println("query: " + query.toString());
  97.  
  98. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  99. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  100.  
  101. System.out.println("**** 查询结果 ");
  102. // 获得总命中数
  103. System.out.println("总命中数:" + topDocs.totalHits);
  104. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  105. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  106. // 根据文档id取存储的文档
  107. Document hitDoc = indexSearcher.doc(sdoc.doc);
  108. System.out.println("-------------- docId=" + sdoc.doc + ",score="
  109. + sdoc.score);
  110. // 取文档的字段
  111. System.out.println("prodId:" + hitDoc.get("prodId"));
  112. System.out.println("name:" + hitDoc.get("name"));
  113. System.out.println("simpleIntro:" + hitDoc.get("simpleIntro"));
  114. System.out.println("price:" + hitDoc.get("price"));
  115.  
  116. System.out.println();
  117. }
  118.  
  119. }
  120. }

9、数值查询

前提:查询的数值字段必须索引。通过 IntPoint, LongPoint, FloatPoint, or DoublePoint 中的方法构建对应的查询。以IntPoint为例:

  1. // 精确值查询
  2. Query exactQuery = IntPoint.newExactQuery("price", 1999900);
  3.  
  4. // 数值范围查询
  5. Query pointRangeQuery = IntPoint.newRangeQuery("price", 499900,1000000);
  6.  
  7. // 集合查询
  8. Query setQuery = IntPoint.newSetQuery("price", 1999900, 1000000,2000000);

完整示例代码

  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5.  
  6. import org.apache.lucene.analysis.Analyzer;
  7. import org.apache.lucene.document.Document;
  8. import org.apache.lucene.document.IntPoint;
  9. import org.apache.lucene.index.DirectoryReader;
  10. import org.apache.lucene.index.IndexReader;
  11. import org.apache.lucene.queryparser.classic.ParseException;
  12. import org.apache.lucene.search.IndexSearcher;
  13. import org.apache.lucene.search.Query;
  14. import org.apache.lucene.search.ScoreDoc;
  15. import org.apache.lucene.search.TopDocs;
  16. import org.apache.lucene.store.Directory;
  17. import org.apache.lucene.store.FSDirectory;
  18.  
  19. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  20.  
  21. /**
  22. * @Description: 数值查询
  23. * @author liguangsheng
  24. * @date 2018年5月12日
  25. *
  26. */
  27. public class PointQueryDemo {
  28. public static void main(String[] args) throws IOException, ParseException {
  29. // 使用的分词器
  30. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  31. // 索引存储目录
  32. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  33. // 索引读取器
  34. IndexReader indexReader = DirectoryReader.open(directory);
  35. // 索引搜索器
  36. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  37.  
  38. // 精确值查询
  39. Query exactQuery = IntPoint.newExactQuery("price", 1999900);
  40. System.out.println("********** pointRangeQuery 数值精确查询 ***********");
  41. doSearch(exactQuery, indexSearcher);
  42.  
  43. // PointRangeQuery 数值范围查询
  44. Query pointRangeQuery = IntPoint.newRangeQuery("price", 499900,
  45. 1000000);
  46. System.out.println("********** pointRangeQuery 数值范围查询 ***********");
  47. doSearch(pointRangeQuery, indexSearcher);
  48.  
  49. // 集合查询
  50. Query setQuery = IntPoint.newSetQuery("price", 1999900, 1000000,
  51. 2000000);
  52. System.out.println("********** pointRangeQuery 数值集合查询 ***********");
  53. doSearch(setQuery, indexSearcher);
  54.  
  55. // 使用完毕,关闭、释放资源
  56. indexReader.close();
  57. directory.close();
  58. }
  59.  
  60. private static void doSearch(Query query, IndexSearcher indexSearcher)
  61. throws IOException {
  62. // 打印输出查询
  63. System.out.println("query: " + query.toString());
  64.  
  65. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  66. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  67.  
  68. System.out.println("**** 查询结果 ");
  69. // 获得总命中数
  70. System.out.println("总命中数:" + topDocs.totalHits);
  71. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  72. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  73. // 根据文档id取存储的文档
  74. Document hitDoc = indexSearcher.doc(sdoc.doc);
  75. System.out.println("-------------- docId=" + sdoc.doc + ",score="
  76. + sdoc.score);
  77. // 取文档的字段
  78. System.out.println("prodId:" + hitDoc.get("prodId"));
  79. System.out.println("name:" + hitDoc.get("name"));
  80. System.out.println("simpleIntro:" + hitDoc.get("simpleIntro"));
  81. System.out.println("price:" + hitDoc.get("price"));
  82.  
  83. System.out.println();
  84. }
  85.  
  86. }
  87. }

总结:不同的查询需求只是不同字段的不同基本查询的组合

三、QueryParser详解

QueryParser 查询解析生成器

Lucene QueryPaser包中提供了两类查询解析器:

A. 传统的解析器:QueryParser和MultiFieldQueryParser

B. 基于新的 flexible 框架的解析器:StandardQueryParser

1. 用法

用法1 传统解析器-单默认字段 QueryParser:

  1. QueryParser parser = new QueryParser("defaultFiled", analyzer);
  2. //parser.setPhraseSlop(2);
  3. Query query = parser.parse("query String");

 用法2  传统解析器-多默认字段  MultiFieldQueryParser:

  1. // 传统查询解析器-多默认字段
  2. String[] multiDefaultFields = { "name", "type", "simpleIntro" };
  3. MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(
  4. multiDefaultFields, analyzer);
  5. // 设置默认的组合操作,默认是 OR
  6. multiFieldQueryParser.setDefaultOperator(Operator.OR);
  7. Query query4 = multiFieldQueryParser.parse("笔记本电脑 AND price:1999900");

 用法3  新解析框架的标准解析器:StandardQueryParser:

  1. StandardQueryParser queryParserHelper = new StandardQueryParser(analyzer);
  2. // 设置默认字段
  3. // queryParserHelper.setMultiFields(CharSequence[] fields);
  4. // queryParserHelper.setPhraseSlop(8);
  5. // Query query = queryParserHelper.parse("a AND b", "defaultField");
  6. Query query5 = queryParserHelper.parse(
  7. "(\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 AND price:1999900","name");

以上3种用法的完整示例代码:

  1. package com.study.lucene.searchdetail;
  2.  
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5.  
  6. import org.apache.lucene.analysis.Analyzer;
  7. import org.apache.lucene.document.Document;
  8. import org.apache.lucene.document.IntPoint;
  9. import org.apache.lucene.index.DirectoryReader;
  10. import org.apache.lucene.index.IndexReader;
  11. import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
  12. import org.apache.lucene.queryparser.classic.ParseException;
  13. import org.apache.lucene.queryparser.classic.QueryParser;
  14. import org.apache.lucene.queryparser.classic.QueryParser.Operator;
  15. import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
  16. import org.apache.lucene.queryparser.flexible.standard.StandardQueryParser;
  17. import org.apache.lucene.search.BooleanClause.Occur;
  18. import org.apache.lucene.search.BooleanQuery;
  19. import org.apache.lucene.search.IndexSearcher;
  20. import org.apache.lucene.search.Query;
  21. import org.apache.lucene.search.ScoreDoc;
  22. import org.apache.lucene.search.TopDocs;
  23. import org.apache.lucene.store.Directory;
  24. import org.apache.lucene.store.FSDirectory;
  25.  
  26. import com.study.lucene.ikanalyzer.Integrated.IKAnalyzer4Lucene7;
  27.  
  28. /**
  29. * @Description: QueryParser示例,查询解析器会对输入的查询短语进行分词
  30. * @author liguangsheng
  31. * @date 2018年5月12日
  32. *
  33. */
  34.  
  35. public class QueryParserDemo {
  36.  
  37. public static void main(String[] args)
  38. throws IOException, ParseException, QueryNodeException {
  39. // 使用的分词器
  40. Analyzer analyzer = new IKAnalyzer4Lucene7(true);
  41. // 索引存储目录
  42. Directory directory = FSDirectory.open(Paths.get("f:/test/indextest"));
  43. // 索引读取器
  44. IndexReader indexReader = DirectoryReader.open(directory);
  45. // 索引搜索器
  46. IndexSearcher indexSearcher = new IndexSearcher(indexReader);
  47.  
  48. /**
  49. * 用法1 传统解析器-单默认字段 QueryParser:
  50. */
  51. // 要搜索的默认字段
  52. String defaultFiledName = "name";
  53. // 查询生成器(解析输入生成Query查询对象)
  54. QueryParser parser = new QueryParser(defaultFiledName, analyzer);
  55. // parser.setPhraseSlop(2);
  56. // 通过parse解析输入,生成query对象
  57. Query query1 = parser.parse(
  58. "(name:\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 AND price:999900");
  59. // 等同query1,如果没有指明要搜索的字段则使用默认值name
  60. Query query2 = parser.parse(
  61. "(\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 AND price:999900");
  62.  
  63. System.out.println("************** query1 ************");
  64. doSearch(query1, indexSearcher);
  65.  
  66. System.out.println("************** query2 ************");
  67. doSearch(query2, indexSearcher);
  68.  
  69. Query query3 = parser.parse(
  70. "(\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 AND price:[800000 TO 1000000]");
  71.  
  72. System.out.println("************** query3 ************");
  73. doSearch(query3, indexSearcher);
  74.  
  75. // 为什么query3查不出结果??? 该如何改
  76. BooleanQuery bquery = new BooleanQuery.Builder()
  77. .add(parser
  78. .parse("(\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 "),
  79. Occur.MUST)
  80. .add(IntPoint.newRangeQuery("price", 800000, 1000000),
  81. Occur.MUST)
  82. .build();
  83.  
  84. System.out.println("************** bquery ************");
  85. doSearch(bquery, indexSearcher);
  86.  
  87. /**
  88. * 用法2 传统解析器-多默认字段 MultiFieldQueryParser:
  89. */
  90. String[] multiDefaultFields = { "name", "type", "simpleIntro" };
  91. MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(
  92. multiDefaultFields, analyzer);
  93. // 设置默认的操作
  94. multiFieldQueryParser.setDefaultOperator(Operator.OR);
  95. Query query4 = multiFieldQueryParser.parse("笔记本电脑 AND price:1999900");
  96.  
  97. System.out.println("************** query4 ************");
  98. doSearch(query4, indexSearcher);
  99.  
  100. /**
  101. * 用法3 新解析框架的标准解析器:StandardQueryParser:
  102. */
  103. StandardQueryParser queryParserHelper = new StandardQueryParser(
  104. analyzer);
  105. // 设置默认字段
  106. // queryParserHelper.setMultiFields(CharSequence[] fields);
  107. // queryParserHelper.setPhraseSlop(8);
  108. // Query query = queryParserHelper.parse("a AND b", "defaultField");
  109. Query query5 = queryParserHelper.parse(
  110. "(\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 AND price:1999900",
  111. "name");
  112.  
  113. System.out.println("************** query5 ************");
  114. doSearch(query5, indexSearcher);
  115.  
  116. // 使用完毕,关闭、释放资源
  117. indexReader.close();
  118. directory.close();
  119. }
  120.  
  121. private static void doSearch(Query query, IndexSearcher indexSearcher)
  122. throws IOException {
  123. // 打印输出查询
  124. System.out.println("query: " + query.toString());
  125.  
  126. // 搜索,得到TopN的结果(结果中有命中总数,topN的scoreDocs(评分文档(文档id,评分)))
  127. TopDocs topDocs = indexSearcher.search(query, 10); // 前10条
  128.  
  129. System.out.println("**** 查询结果 ");
  130. // 获得总命中数
  131. System.out.println("总命中数:" + topDocs.totalHits);
  132. // 遍历topN结果的scoreDocs,取出文档id对应的文档信息
  133. for (ScoreDoc sdoc : topDocs.scoreDocs) {
  134. // 根据文档id取存储的文档
  135. Document hitDoc = indexSearcher.doc(sdoc.doc);
  136. System.out.println("-------------- docId=" + sdoc.doc + ",score="
  137. + sdoc.score);
  138. // 取文档的字段
  139. System.out.println("prodId:" + hitDoc.get("prodId"));
  140. System.out.println("name:" + hitDoc.get("name"));
  141. System.out.println("simpleIntro:" + hitDoc.get("simpleIntro"));
  142. System.out.println("price:" + hitDoc.get("price"));
  143.  
  144. System.out.println();
  145. }
  146.  
  147. }
  148. }

2. 使用查询解析器前需考虑三点

1. 查询字符串应是由人输入的,而不应是你编程产生。如果你为了用查询解析器,而在你的应用中编程产生查询字符串,不可取,更应该直接使用基本查询API;

2. 未分词的字段,应直接使用基本查询API加入到查询中,而不应使用查询解析器;

3. 对于普通文本字段,使用查询解析器,而其他值字段:如 时间、数值,则应使用基本查询API

3. 查询描述规则语法(查询解析语法)

3.1 Term 词项:

  单个词项的表示:     电脑

  短语的表示: "联想笔记本电脑"

3.2 Field 字段:

字段名:

  示例: name:“联想笔记本电脑” AND type:电脑

  如果name是默认字段,则可写成: “联想笔记本电脑” AND type:电脑

  如果查询串是:type:电脑 计算机 手机,只有第一个是type的值,后两个则是使用默认字段,翻译为type:动脑 OR name:计算机 OR name:手机

3.3 Term Modifiers 词项修饰符:

通配符:

? 单个字符

* 0个或多个字符

示例:te?t test* te*t

注意:通配符不可用在开头。

模糊查询,词后加 ~

示例: roam~

模糊查询最大支持两个不同字符。

示例: roam~1

正则表达式: /xxxx/

示例: /[mb]oat/

临近查询,短语后加 ~移动值

示例: "jakarta apache"~10

 范围查询:

mod_date:[20020101 TO 20030101]       包含边界值

title:{Aida TO Carmen} 不包含边界值

词项加权:

使该词项的相关性更高,通过 ^数值来指定加权因子,默认加权因子值是1

示例:如要搜索包含 jakarta apache 的文章,jakarta更相关,则:

jakarta^4 apache

短语也可以: "jakarta apache"^4 "Apache Lucene"

3.4  Boolean 操作符

Lucene支持的布尔操作: AND, “+”, OR, NOT ,"-"

AND:

"jakarta apache" AND "Apache Lucene"

+ 必须包含:

+jakarta lucene

OR:

"jakarta apache" jakarta = "jakarta apache" OR jakarta

NOT 非:

"jakarta apache" NOT "Apache Lucene“

注意:NOT不可单项使用: NOT “Apache Lucene“ 是不对的

- 同NOT:

"jakarta apache" -"Apache Lucene“

3.5 组合 ()

字句组合:

(jakarta OR apache) AND website

字段组合:

title:(+return +"pink panther")

3.6  转义 \

对语法字符: + - && || ! ( ) { } [ ] ^ “ ~ * ? : \ /     进行转义。

如要查询包含 (1+1):2需要转义为\(1\+1\)\:2

源码获取地址:

https://github.com/leeSmall/SearchEngineDemo

Lucene系列六:Lucene搜索详解(Lucene搜索流程详解、搜索核心API详解、基本查询详解、QueryParser详解)的更多相关文章

  1. [lucene系列笔记3]用socket把lucene做成一个web服务

    上一篇介绍了用lucene建立索引和搜索,但是那些都只是在本机上运行的,如果希望在服务器上做成web服务该怎么办呢? 一个有效的方法就是用socket通信,这样可以实现后端与前端的独立,也就是不管前端 ...

  2. Lucene系列五:Lucene索引详解(IndexWriter详解、Document详解、索引更新)

    一.IndexWriter详解 问题1:索引创建过程完成什么事? 分词.存储到反向索引中 1. 回顾Lucene架构图: 介绍我们编写的应用程序要完成数据的收集,再将数据以document的形式用lu ...

  3. Lucene系列三:Lucene分词器详解、实现自己的一个分词器

    一.Lucene分词器详解 1. Lucene-分词器API (1)org.apache.lucene.analysi.Analyzer 分析器,分词器组件的核心API,它的职责:构建真正对文本进行分 ...

  4. Solr系列六:solr搜索详解优化查询结果(分面搜索、搜索结果高亮、查询建议、折叠展开结果、结果分组、其他搜索特性介绍)

    一.分面搜索 1. 什么是分面搜索? 分面搜索:在搜索结果的基础上进行按指定维度的统计,以展示搜索结果的另一面信息.类似于SQL语句的group by 分面搜索的示例: http://localhos ...

  5. Lucene系列-搜索

    Lucene搜索的时候就要构造查询语句,本篇就介绍下各种Query.IndexSearcher是搜索主类,提供的常用查询接口有: TopDocs search(Query query, int n); ...

  6. Lucene系列二:Lucene(Lucene介绍、Lucene架构、Lucene集成)

    一.Lucene介绍 1. Lucene简介 最受欢迎的java开源全文搜索引擎开发工具包.提供了完整的查询引擎和索引引擎,部分文本分词引擎(英文与德文两种西方语言).Lucene的目的是为软件开发人 ...

  7. Lucene系列一:搜索引擎核心理论

    一.为什么需要搜索引擎 问题1:数据库索引的原理是怎样的? 索引原理:对列值创建排序存储,数据结构={列值.行地址}.在有序数据列表中就可以利用二分查找快速找到要查找的行的地址,再根据地址直接取行数据 ...

  8. Lucene系列-索引文件

    本文介绍下lucene生成的索引有哪些文件组成,每个文件包含了什么信息.基于Lucene 4.10.0. 数据结构 索引(index)包含了存储的文档(document)正排.倒排信息,用于文本搜索. ...

  9. Lucene系列-分析器

    分析器介绍 搜索的基础是对文本信息进行分析,Lucene的分析工具在org.apache.lucene.analysis包中.分析器负责对文本进行分词.语言处理得到词条,建索引和搜索的时候都需要用到分 ...

随机推荐

  1. 15个Spring的核心注释示例

    众所周知,Spring DI和Spring IOC是Spring Framework的核心概念.让我们从org.springframework.beans.factory.annotation和org ...

  2. iOS应用管理(优化)

    // //  ViewController.m //  01-应用管理 //  Created by apple on 17-5-14. //  Copyright (c) 2017年  All ri ...

  3. c#:使用using关键字自动释放资源未必一定就会有明显好处

    public string ToXML() { string strXml = string.Empty; try { MemoryStream ms = new MemoryStream(); Xm ...

  4. 豆瓣源安装requirements.txt

    豆瓣源安装requirements.txt pip install -i https://pypi.doubanio.com/simple/ -r requirements.txt

  5. Python爬虫设置Headers

    Python设置Headers import urllib import urllib2 url = 'http://www.server.com/login' user_agent = 'Mozil ...

  6. JIRA python篇之展示多人未完成任务列表

    [本文出自天外归云的博客园] 通过python中的jira类我们可以方便的操作jira,获取一些我们想要再加工的信息. 这里举例,用html页面的形式展示分派给组内每个人的任务(未完成的.正在进行中的 ...

  7. PHP error_reporting() 函数

    实例 规定不同的错误级别报告: <?php // 关闭错误报告 error_reporting(0); // 报告 runtime 错误 error_reporting(E_ERROR | E_ ...

  8. [转]MySQL如何设置自动增长序列 SEQUENCE

    原文地址:https://blog.csdn.net/czbqoo01/article/details/70148516 解决思路:由于mysql不带sequence,所以要手写的,创建一张储存seq ...

  9. Bootstrap tab插件的使用

    菜鸟教程链接:http://www.runoob.com/bootstrap/bootstrap-tab-plugin.html 1.例子 <!DOCTYPE html> <html ...

  10. PHP判断当前页面是电脑登录,还是手机登录

    //判断是否是电脑登录,还是手机登录 public function isMobil() { $useragent = isset($_SERVER['HTTP_USER_AGENT']) ? $_S ...