Lucene5学习之QueryParser-Query解析器

  Lucene已经给我们提供了很多Query查询器,如PhraseQuery,SpanQuery,那为什么还要提供QueryParser呢?或者说设计QueryParser的目的是什么?QueryParser的目的就是让你从众多的Query实现类中脱离出来,因为Query实现类太多了,你有时候会茫然了,我到底该使用哪个Query实现类来完成我的查询需求呢,所以Lucene制定了一套Query语法,根据你传入的Query语法字符串帮你把它转换成Query对象,你不用关心底层是使用什么Query实现类。

      上面既然说到PhraseQuery和SpanQuery,那我就随带扯一扯这两个Query的区别吧,我估计这是很多初学Lucene者比较困惑的问题,两个Query都能根据多个Term进行查询,但PhraseQuery只能按照查询短语在文档中出现的顺序进行匹配,而不能颠倒过来匹配,比如你查询quick lazy,而索引中出现的是xxxxxxxxlazy qucikxxxxxxx,那PhraseQuery就没法匹配到了,这时候你就只能使用SpanQuery了,SpanQuery的inorder参数允许你设置是否按照查询短语在文档中出现的顺序进行匹配,以及是否允许有重叠,什么叫是否允许重叠?举个例子说明,假如域的值是这样的:“jumps over extremely very lazy broxn dog”,而你的查询短语是“dog over”,因为索引中dog在over后面,而你提供的查询短语中dog却在over前面,这与它在索引文档中出现的顺序是颠倒的,这时候你就不能使用PhraseQuery,PhraseQuery只能按出现顺序匹配,这种颠倒顺序匹配无法用PhraseQuery实现,把SpanQuery的inOrder设为false,就可以无视顺序了,即只要你能按slop规定的步数内匹配到dog over或者 over dog都算匹配成功。而如果inOrder设为true,意思就是你只能在规定步数内匹配到dog over,而匹配到over dog不算,并且匹配过程中不能有重叠。什么叫重叠?要得到dog over,那只能把over往右移动6步,可是它跨过了dog了,即dog重叠了,意思就是你只能在两者之间移动,不能跨越两者的边界进行匹配。我解释的不知道你们能看的明白不?注意两者的slop都是最多需要移动几步的意思即在规定步数内达到你想要的情况。

    跑题扯了半天PhraseQuery和SpanQuery的区别,回归正题,接着说说QueryParser的查询语法,关于QueryParser的语法,我们还是去看Lucene的官方Wiki吧,

https://lucene.apache.org/core/2_9_4/queryparsersyntax.html

 

Html代码  

  1. Overview  
  2.   
  3. Although Lucene provides the ability to create your own queries through its API, it also provides a rich query language through the Query Parser, a lexer which interprets a string into a Lucene Query using JavaCC.  
  4.   
  5. Generally, the query parser syntax may change from release to release. This page describes the syntax as of the current release. If you are using a different version of Lucene, please consult the copy of docs/queryparsersyntax.html that was distributed with the version you are using.  
  6.   
  7. Before choosing to use the provided Query Parser, please consider the following:  
  8.   
  9. If you are programmatically generating a query string and then parsing it with the query parser then you should seriously consider building your queries directly with the query API. In other words, the query parser is designed for human-entered text, not for program-generated text.  
  10. Untokenized fields are best added directly to queries, and not through the query parser. If a field's values are generated programmatically by the application, then so should query clauses for this field. An analyzer, which the query parser uses, is designed to convert human-entered text to terms. Program-generated values, like dates, keywords, etc., should be consistently program-generated.  
  11. In a query form, fields which are general text should use the query parser. All others, such as date ranges, keywords, etc. are better added directly through the query API. A field with a limit set of values, that can be specified with a pull-down menu should not be added to a query string which is subsequently parsed, but rather added as a TermQuery clause.  

   概述里提到QueryParser是通过JavaCC把用户输入的String转换成Query对象,那什么是JavaCC?我找到一段官方的介绍:

 

   

Java代码  

  1. Java Compiler Compiler tm (JavaCC tm) is the most popular parser generator for use with Java tm applications. A parser generator is a tool that reads a grammar specification and converts it to a Java program that can recognize matches to the grammar. In addition to the parser generator itself, JavaCC provides other standard capabilities related to parser generation such as tree building (via a tool called JJTree included with JavaCC), actions, debugging, etc.  

   JavaCC就是一个非常流行的用Java写的解析器生成器。

 

   Before choosing to use the provided Query Parser, please consider the following:
  意思就是提醒我们在选择使用QueryParser之前请先仔细考虑下面3个问题。

  1.QueryParser是为用户输入文本而设计的而不是你应用程序生成的文本而设计的,什么意思?意思就是你要考虑最恶劣的情况,因为用户输入的文本是无法预知的,你不能试图去规范用户输入什么样格式的查询字符串,如果你正在准备这么做,请你还是去使用Query api 构建你的Query实现类吧。

  2.没有分词的域请直接使用Query API来构建你的Query实现类,因为QueryParser会使用分词器对用户输入的文本进行分词得到N个Term,然后再根据匹配的,这点你必须清楚。

  3.第3点里提示你在设计查询表单时,对应普通的文本框可以直接使用QueryParser,但像日期范围啊搜索关键字啊下拉框里选定某个值或多个值进行限定值时,请使用Query API去做。

 

  Term:
  Term直接用一个单词表示,如“hello” ,多个Term用空格分割,如“hello java”,

  

  Field:
  可以添加上域,域和Term字符串用冒号隔开,如title:"The Right Way",查询多个域用or或者and连接,

  如title:"The Right Way" AND text:go

 

  Term字符串你还可以使用通配符进行模糊匹配,如title: ja*a  title:ja?a title:ja*等等

  你还可以使用~字符开启FuzzyQuery,如title:roam~ or title:roam~0.8
  相似度阀值取值范围是0-1之间,默认值是0.5,

  

  QueryParser语法表达式还支持开启PhraseQuery短语查询,如title:"jakarta apache"~10

  表示查询title域中包含jakarta和apache字符且jakarta在apache前面且jakarta与apache之间间隔距离在10个间距之内(即<=10)。

 

  当然也支持范围查询,title:[java to php],age[18 to 28]

 

  你也可以单独为某个Term设置权重,如title:java^4,默认权重都为1.

  

  Boolean Operators即boolean操作符即or和and,用来链接多个Term的,如果两个Term仅仅用空格隔开,则默认为or链接的,如title:java^5 and content:lucen*

 

  当然还有+ -字符,表示必须符合和必须不符合即排除的意思,如+jakarta lucene,但注意只有一个Term的时候,不能用NOT,比如NOT "jakarta apache"是不合法的。

  而这样就可以,"jakarta apache" -"Apache Lucene"表示必须包含jakarta apache,但不能包含Apache Lucene.

 

  当or and条件很复杂时,需要限制优先级时可以用()小括号对Term条件进行分组,如(jakarta OR apache) AND website

 

  当对某个域的限定值有多个可以用or/and进行链接,也可以用()写在一起,如title:(+return +"pink panther"),当然你也可以用and拆成title:return and title:"pink panther"

 

  Lucene中需要进行转义的特殊字符包括

  + - && || ! ( ) { } [ ] ^ " ~ * ? : \

 

  

  QueryParser使用示例如下:

Java代码  

  1. QueryParser parser = new QueryParser(fieldName, new IKAnalyzer());  
  2. Query query = parser.parse(queryString);  

  queryString即为上面解释的那些queryParser查询表达式。

 

  但QueryParser并不能完全代替Query API,它并不能实现所有Query实现类的功能,比如它不支持SpanQuery.

 

  上面说的都是在单个域中查询,当然要在多个域中查询你可以使用or/and进行拼接,如果要在多个域中进行查询,你除了用or/and拼接以外,多了另一种选择,它就是MultiFieldQueryParser.我想Google大家都用过,Google的搜索界面就为我们提供了一个搜索输入框,用户只需要输入搜索关键字即可,而不用关心我输入的搜索关键字接下来会在哪些域(Field)里去查找,可能底层我们的索引会建立title,content,category等各种域,会依次从这几个域中去匹配是否有符合用户输入的查询关键字,但这些对用户都是透明的,用户也没必要去了解这些,MultiFieldQueryParser就是用来解决这种多域查询问题的。

  

Java代码  

  1. public MultiFieldQueryParser(String[] fields, Analyzer analyzer, Map<String,Float> boosts) {  
  2.     this(fields, analyzer);  
  3.     this.boosts = boosts;  
  4.   }  

 这是MultiFieldQueryParser的构造函数,首先fields毫无疑问就是提供一个域名称数组即你需要在哪些域中进行查询,analyzer即分词器对象,用户输入的搜索关键字我们需要对其分词,为什么要分词?因为用户输入的搜索关键字可能是一句话,比如:我女朋友要跟我分手,我该怎么办,分词后可能得到的只有两个关键字就是女朋友和分手,其他都是停用词被剔除了。最后一个boosts参数是一个map对象,是用来设置每个域的权重加权值的,map的key就是域名称,value就是加权值。boosts参数可以不传入,你传入一个null也行,不传入即表示不进行特殊加权,则默认权重加权值都是1.

 

  OK,有关QueryParser的知识就说这么多了,打完收工!!!

 

    如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

转载:http://iamyida.iteye.com/blog/2198176

时间: 2024-12-21 01:12:13

Lucene5学习之QueryParser-Query解析器的相关文章

Lucene5学习之使用IKAnalyzer分词器

   之前的示例中,使用的是默认的StandardAnalyzer分词器,不能有效的进行中文分词,下面演示下如何在Lucene5.0中使用IKAnalyzer分词器.     首先下载IKAnalyzer分词器源码,IKAnalyzer分词器源码托管在OSChina的git上.下载地址: http://git.oschina.net/wltea/IK-Analyzer-2012FF 请如图下载IK的源代码:    然后打开Eclipse新建一个Java Project:      然后解压下载下

Lucene5学习之自定义同义词分词器简单示例

  同义词功能在全文搜索时的意义,大家应该都懂的.今天中文我就试着写了一个同义词分词的示例demo,其实主要代码还是参考Lucene in Action 这本英文版书籍的随书代码,只不过Lucenen in Action书里的示例代码目前最新版只支持到Lucene4.x,对于Lucene5.x,代码需要稍作修改,下面是基于Lucene5.x的自定义同义词分词器demo:   Java代码   package com.yida.framework.lucene5.analyzer.synonym;

Lucene5学习之使用MMSeg4j分词器

     MMSeg4j是一款中文分词器,详细介绍如下:        1.mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法(http://technology.chtsai.org/mmseg/ )实现的中文分词器,并实现 lucene 的 analyzer 和 solr 的TokenizerFactory 以方便在Lucene和Solr中使用.          2.MMSeg 算法有两种分词方法:Simple和Complex,都是基于正向最大匹配.Complex 加了四

Lucene5学习之使用Ansj-seg分词器

    这回我们来玩玩ansj分词器,由于Lucene5.0在API上有点小变化,需要修改ansj分词器源码,重新打包jar包,然后mvn install到本地仓库才能引用到项目中.至于怎么修改以及怎么打包jar,我就不过多说明了,有点麻烦,我想偷个懒,哈哈.这里我就直接把打包后的jar分享给你们,jar包注意在底下的附件里下载.     我就说说,怎么在项目中使用ansj分词器,首先pom.xml引入ansj分词器的依赖.   Xml代码   <!-- ansj-seg -->   <

仅用500行Python代码实现一个英文解析器的教程_python

语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理.自然语言引入了很多意外的歧义,以我们对世界的了解可以迅速地发现这些歧义.举一个我很喜欢的例子: 正确的解析是连接"with"和"pizza",而错误的解析将"with"和"eat"联系在了一起: 过去的一些年,自然语言处理(NLP)社区在语法分析方面取得了很大的进展.现在,小小的 Python 实现可能比广泛应用的 Stanford 解析器表现得更出色. 文章剩下

Solr所有的查询解析器Query Parsers(转:http://blog.csdn.net/jiangchao858/article/details/53859731)

摘要: Solr除了支持常见的解析器之外,还有一些特殊用途的解析器,为了便于之后查阅,总结一下.本文整理自Solr官方文档. 解析器 说明 Standard Query Parser Solr的标准查询解析器Standard Query Parser DisMax Query Parser Solr的查询解析器DisMax Query Parser Extended DisMax Query Parser Solr的查询解析器The Extended DisMax Query Parser Bl

Lucene5学习之多线程创建索引

    昨晚睡觉前把多线程创建索引demo写好了,今天早上7点多就起来,趁着劲头赶紧记录分享一下,这样对那些同样对Lucene感兴趣的童鞋也有所帮助.     我们都知道Lucene的IndexWriter在构造初始化的时候会去获取索引目录的写锁writerLock,加锁的目的就是保证同时只能有一个IndexWriter实例在往索引目录中写数据,具体看截图:  而在多线程环境下,光保证只有IndexWriter实例能得到锁还不行,还必须保证每次只能有一个线程能获取到writerLock,Luce

Lucene5学习之LuceneUtils工具类简单封装

     周六花了整整一下午,将Lucene5中有关索引的常见操作进行了简单封装,废话不多说,上代码:   Java代码   package com.yida.framework.lucene5.util;      import java.io.IOException;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.locks.Lock;   import java.util.concu

Lucene5学习之自定义排序

         在Lucene5学习之排序-Sort中,我们已经学习了Sort的用法,已经了解了,Lucene搜索返回的命中结果默认是按照索引文档跟搜索关键字的相关度已经排序的,而相关度又是基于内部的打分机制和索引文档id,内部的打分机制则是根据Term的IDF-TF以及创建索引时Field的boost等决定的,默认是按照得分降序排序,得分相同再按docId升序排序.如果你觉得默认的排序方式满足不了你的需求,你可以设置SortField按照特定的域来排序,特定的域排序其实根据域的type类型去