为什么80%的码农都做不了架构师?>>>
本文介绍了Lucene查询构造的几种方法。
1.查询方式简介
查询构造的方法主要有两种,第一种是Query,另外一种是Queryparser,两者有明显的差别。QueryParer类用来转换用户的检索关键词,其作用就是把用户输入的非格式化检索词转换为后台检索可以理解的Query对象。用Queryparser时需要一个参数,就是Analyzer,如果要进行分词处理的话就必须要这样的一个参数。
1 2 3 4 5 6 7 | String querystring="...."; Analyzer analyzer =newStandardAnalyzer(Version.LUCENE_42); QueryParser parser=newQueryParser(Version.LUCENE_42,"body",analyzer); Query query=parser.parse(querystring); Filter filter =null;//查询过滤器 TopDocs topDocs = searcher.search(query, filter,10);//最后一个参数,限制查询结果的条目。 |
Query类则是一个抽象类,需要使用Query的某个子类的构造函数来实例化并以此来表示与用户检索有关的内容。具体使用的时候,用户可以通过Query的一系列子类,如TermQuery/BooleanQuery/RangeQuery/PrefixQuery/PhraseQuery/MultiPhraseQuery/FuzzyQuery/WildcardQuery/SpanQuery/Regexuery的构造函数来直接生成对应的Query对象。
2.查询方式详解
TermQuery词条检索
这是最简单的检索,入门教程当中使用的就是这样的检索构造。
1 2 | Term proposedquery=newTerm(“body”,”php”);//前面是域,后面是检索词; Query query=newTermQuery(proposedquery); |
Term里面的检索词只能是单个词语,否则检索不到任何内容,因此这里没有对检索词进行任何形式的处理,它默认就把你提供的检索词去进行检索了。如果需要对检索词进行进一步的处理,比如分词,就必须使用QueryParser类。
1 2 3 4 5 6 7 | String querystring="....";//这里填写检索词,Analyzer会对其进行分词处理,默认是进行逻辑或运算。 Analyzer analyzer =newStandardAnalyzer(Version.LUCENE_42); QueryParser parser=newQueryParser(Version.LUCENE_42,"body",analyzer); Query query=parser.parse(querystring); Filter filter =null;//查询过滤器 TopDocs topDocs = searcher.search(query, filter,10);//最后一个参数,限制查询结果的条目。 |
BooleanQuery词条检索
首先创建Term项,生成TermQuery,在通过BooleanQuery生成实例化对象,最后调用这个实例对象的add方法把几个TermQuery对象添加进来。
只有知道什么是布尔逻辑就很容易理解布尔查询,布尔查询主要有三种:AND/OR/NOT
但是在实际的参数传递时,并不是传递的这三个值,二十其代替形式,如下表:
AND | BooleanClause.Occur.MUST |
NOT | BooleanClause.Occur.MUST_NOT |
OR | BooleanClause.Occur.SHOULD |
下面我们就来看实际的例子:
1 2 3 4 5 6 7 8 | Term term1=newTerm("body","php"); Term term2=newTerm("body","java"); TermQuery q1=newTermQuery(term1); TermQuery q2=newTermQuery(term2); BooleanQuery query=newBooleanQuery(); query.add(q1, BooleanClause.Occur.MUST); query.add(q2, BooleanClause.Occur.SHOULD); |
上面查询语句表示:查找所有含有PHP,可能还含有java的文档。
而在QueryParser查询的时候则直接使用AND/OR/NOT即可:
1 2 3 4 | String querystring="java AND php";//这里填写检索词,Analyzer会对其进行分词处理,默认是进行逻辑或运算。 Analyzer analyzer =newStandardAnalyzer(Version.LUCENE_42); QueryParser parser=newQueryParser(Version.LUCENE_42,"body",analyzer); Query query=parser.parse(querystring); |
上面查询语句的意思是:查询既含有Php又含有java的文档集。
RangeQuery词条检索
该检索项在lucene4.2.1中已经没有了,取而代之的有两个方法:分别为NumericRangeQuery和TermRangeQuery。
首先来看TermRangeQuery
这是官方文档的描述,这里我提供其构造函数的形式。
This query matches the documents looking for terms that fall into the supplied range according to Byte.compareTo(Byte). It is not intended for numerical ranges; use NumericRangeQuery instead.
TermRangeQuery(String field, BytesRef lowerTerm, BytesRef upperTerm, boolean includeLower, boolean includeUpper)
Constructs a query selecting all terms greater/equal than lowerTerm but less/equal than upperTerm.
然后来看看NumericRangeQuery,文档中对其有非常详细的描述,想了解的自行查询看API。
A Query that matches numeric values within a specified range. To use this, you must first index the numeric values using IntField, FloatField, LongField or DoubleField (expert: NumericTokenStream). If your terms are instead textual, you should use TermRangeQuery. NumericRangeFilter is the filter equivalent of this query.
创建方式如下:
1 | Query q = NumericRangeQuery.newFloatRange("weight",0.03f,0.10f,true,true); |
PrefixQuery词条检索
使用term构造的term对象作为PrefxQuery的生成参数,得到的结果是以term项内的文本值为开头字符的所有文档,和MULTIPHRASE不同,它不能过滤内容,只能全盘接受。
下面给出例子:
1 2 | String text1 ="001"; doc.add(newField("fieldname",text1,TextField.TYPE_STORED)); |
然后给出查询:
1 2 | Term prefix=newTerm("fieldname","00"); PrefixQuery query=newPrefixQuery(prefix); |
假如使用QueryParser的话,则只需要使用通配符即可:
1 | String querystring="人*工";//其中*可以代替任何字符; |
MultiPhraseQuery词条检索
当需要检索部分带有相同的前缀的词汇时,例如,当用户需要检索”声带“、”声音“,则可以把前缀设置为”声“,后缀设置为”带“和“音”。这样一个前缀和多个后缀共同构造成了检索词:
1 2 3 | MultiPhraseQuery query=newMultiPhraseQuery(); query.add(newTerm("body","am"));//前缀 query.add(newTerm("body","php"));//后缀 |
FuzzyQuery词条检索
模糊检索不同于签署的通配符检索,它是以文本的额编辑距离作为相似度来进行判断的,编辑距离是两个不同的字符串需要经多少次编辑和变化才能转化为对方,通常的编辑行为包括增加一个检索项,删除一个检索项、修改一个检索项。
1 2 | Term term1=newTerm("body","pha"); FuzzyQuery query=newFuzzyQuery(term1); |
这个检索可以检索出含有PHP的文档集合。Term term1=new Term(“body”,”jaiv”);则可以检索出含有java的文档。
如果使用QueryParser则可以在检索词后面加上~0.1f;
String searchword=”jav~0.1f”;
其相关的构造函数有:
PhraseQuery词条检索
PhraseQuery有两个需要特别注意的地方,第一个是它可以设置坡度:setslop;表面在两个关键词之间可以插入多少个字符,默认为0;两外一个就是检索的时候严格符合关键词的添加顺序。
1 2 3 4 5 | PhraseQuery query=newPhraseQuery(); query.add(newTerm("body","i")); query.add(newTerm("body","php")); query.setSlop(10);//允许i和php中间插入10个字 |
如果使用QueryParser则只需要在给查询项加上双引号,带空格的多个检索词会生成”与“关系。
String searchwords=”\”JAVA PHP\” “;//记得讲述转义字符。
此外还有FilteredQuery、NGramPhraseQuery等等,这里不再详细解释了,如需了解,自行查看文档:API
FilteredQuery(Query query, Filter filter)
Constructs a new query which applies a filter to the results of the original query.
FilteredQuery(Query query, Filter filter, FilteredQuery.FilterStrategy strategy)
Expert: Constructs a new query which applies a filter to the results of the original query.