写这篇博客第一个是为了记录在solr中自定义queryParser(顺便介绍一下solr的queryParser),第二个是在 http://suichangkele.iteye.com/blog/2363599 (自定义得分的PrefixQuery)这篇博客中也说了要在solr中使用自己的query要使用自己的queryParser,第三个是公司业务需求,需要实现更加智能的搜索提示(智能是我自己给加的)。因为以上的原因我自己写了一个queryParser来实现我心中理想的搜索提示(先声明一下,我这里使用的是solr5.5.3的版本)。
1、solr中的queryParser:为什么我们在solr中设置q=*:*就能匹配所有的doc呢?为什么q=name:黄*就能匹配所有的name域是以黄开头的doc呢?原理就是solr使用queryParser将输入的q解析为了一个query,然后使用这个query进行了搜索。solr中有很多的queryParser,比如我们熟知的有lucene、dismax、edismax。我们从solr的源码中来仔细看一下吧:org.apache.solr.search.QParserPlugin在这个类中,可以发现有一个map,在加载org.apache.solr.search.QParserPlugin的时候就会忘这个map中添加很多的内容,在这个map中就能找到我们熟悉的lucene、dismax、edismax,不过他们都不是QueryParser,而是QParserPlugin,不过在QParserPlugin这个类中有createParser方法,用于产生一个QueryParser。我们在solrconfig.xml中可以配置QParserPlugin,在searchHandler中也可以配置defType表示使用的QParserPlugin,使用的名字就是在这个map中存放的内容。在org.apache.solr.search.QParserPlugin类中有一个默认的DEFAULT_QTYPE,也就是在一次查询的时候不指定defType的话默认就是使用这个QTYPE,他便是lucene,也就是使用LuceneQParserPlugin来生成要使用的QueryParser。
2、在solrconfig.xml中定义自己的queryParser 很简单,只要继承org.apache.solr.search.QParserPlugin这个类,实现他的createParser方法即可,然后再solrconfig.xml中配置一下。我这里先做一个最简单的,比如我们把所有的q都转化为query的value,并且需要指定一个默认的域作为query的key(加入说是id域吧),然后封装为一个TermQuery(如此一来,即使你搜q=黄*,我也给你生成一个TermQuery,即:id:黄*,注意这个并不是PrefixQuery,仍然是一个TermQuery,只不过value的部分是黄*).代码如下:
public class TermQueryParserPlugin extends QParserPlugin{ private Logger logger = LoggerFactory.getLogger(TermQueryParserPlugin.class); @Override public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { logger.info("解析q:{}",qstr); return new QParser(qstr,localParams,params,req) {//因为逻辑简单,所以直接使用一个匿名内部类,实现其parser方法即可 SolrParams solrParams = SolrParams.wrapDefaults(localParams, params);//将客户端传来的和本地配置的参数合并 @Override public Query parse() throws SyntaxError { String df = solrParams.get("df");//从合并后的参数中去的df参数 try { return new TermQuery(new Term(df, new BytesRef(qstr.getBytes("UTF-8")))){ public String toString(String s) {//重写的目的是为了在页面好看区别来 return "这是一个termQuery"; }; }; } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } }; } }
然后再在solrconfig.xml中配置 <queryParser name="helloword" class="xxxxx.TermQueryParserPlugin"/>,然后再浏览器中访问你的solr,使用的url为:
http://localhost:8080/solr/product/select?q=黄*&wt=json&indent=true&debugQuery=true&defType=helloword&df=id 后面的参数很重要,倒数第三个是开启debug,倒数第二个是指定使用的queryParserPlugin,使用我们上面配置的helloword,第三个参数是因为我们在自定义的queryParser中要使用(不要和dismax中的df混淆了)。可以发现debug的信息:debug":{
"rawquerystring":"黄*", "querystring":"黄*", "parsedquery":"id:黄*", "parsedquery_toString":"这是一个termQuery",
这样我们就能实现自己的queryParser了。
3、我自己实现的使用ScoredPrefixQuery的queryParser做提示(ScoredPrefixQuery参见http://suichangkele.iteye.com/blog/2363599 博客)
我们的要求是这样的:假设我要提示 特仑苏牛奶,
1、当用于输入t时要输入,telunsuniu时也要输入,即对整个的拼音建立索引并使用前缀查询
2、当用户输入tlsn时提示,即对整个拼音的建立索引,使用前缀搜索
3、当用户输入niun时也要提示,即对分词后的term的拼音建立索引,使用前缀查询
4、当用户输入tl或者nn时提示,即对分词后的term的拼音的前缀建立索引,使用前缀搜索
5、当用户输入牛奶、牛、特伦时提示,即对分词建立索引,查询时使用前缀搜索
写到这我们便明白了要对任何一个输入词做五个域的查询,很显然这个很符合dismaxquery,所以我这里的QueryParser就直接继承了DismaxQueryParser,因为他里面有很多的方法可以直接拿来用。
/** 用于做提示用的QParser*/ public class SuggestQParser extends DisMaxQParser { private static Logger logger = LoggerFactory.getLogger(SuggestQParser.class); public SuggestQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { super(qstr, localParams, params, req); } @Override public Query parse() throws SyntaxError { SolrParams solrParams = SolrParams.wrapDefaults(localParams, params);//将多个参数合并 queryFields = parseQueryFields(req.getSchema(), solrParams);//获得查询的域以及boost,在这里 /* * the main query we will execute. we disable the coord because this * query is an artificial construct */ BooleanQuery query = new BooleanQuery(true); boolean notBlank = addMainQuery(query, solrParams); if (!notBlank) return null; return query; } protected boolean addMainQuery(BooleanQuery query, SolrParams solrParams) throws SyntaxError { //得到tie float tiebreaker = solrParams.getFloat(DisMaxParams.TIE, 0.0f); // 得到用户的输入词 String userQuery = getString(); if (userQuery == null) { throw new RuntimeException("ScoredPrefixQueryParser中不接收空的query,不能使用q.alt参数"); } else { //1、使用iK进行分词 //2、循环所有的token,每一个token按照df形成一个ScoredPrefixQuery和termQuery,所有df的形成的query封装为一个DisjunctionMaxQuery,并添加到BooleqnQuery中,关系为optional Analyzer ar = new IKAnalyzer(true); try { int termCount = 0; TokenStream stream = ar.tokenStream("", userQuery); TermToBytesRefAttribute termAttribute = stream.addAttribute(TermToBytesRefAttribute.class); BytesRef bf = termAttribute.getBytesRef();//用于存放字符串的东西。 stream.reset(); while(stream.incrementToken()) { //循环token termAttribute.fillBytesRef();//重新放入字符串。 termCount++; //每个term形成一个DisjunctionMaxQuery DisjunctionMaxQuery dis = new DisjunctionMaxQuery(tiebreaker); String term = bf.utf8ToString();//得到字符串。 logger.info("分词的结果:序号:{},term:{}",new Object[]{termCount,term}); for(String field:queryFields.keySet()){//循环qf,也就是上面中提到的五个域 //形成一个得分的prefixQuery Query prefixQ = new ScoredPrefixQuery(new Term(field, term)); dis.add(prefixQ); } query.add(dis,Occur.SHOULD);//添加该term的dis } query.setMinimumNumberShouldMatch(termCount);//这个的目的为了匹配所有的分析的term logger.info("最后形成的booleanQuery:{}",query); } catch (IOException e) { logger.error("处理分词的时候发生错误,字符串为:{}", new Object[]{userQuery},e); return false; }finally { if(ar != null) ar.close(); } } return true; } }
至此,自己实现queryParser、使用之前写的ScoredPrefixQuery以及实现提示词的queryParser便完成了。
相关推荐
总的来说,QueryParser.jj是Lucene查询解析过程中的基石,它通过JavaCC生成的代码将用户的自然语言查询转换为搜索引擎能够理解的查询结构,从而实现高效的信息检索。掌握QueryParser.jj的内涵,有助于开发者更深入地...
queryparser
标题中的"PyPI 官网下载 | queryparser-python2-0.3.tar.gz"表明这是一个在Python Package Index(PyPI)官方源上发布的软件包,名为`queryparser-python2-0.3`,且格式为tar.gz。PyPI是Python开发者分享和分发自己...
lucene-queryparser-4.9.0.jar
赠送jar包:lucene-queryparser-6.6.0.jar; 赠送原API文档:lucene-queryparser-6.6.0-javadoc.jar; 赠送源代码:lucene-queryparser-6.6.0-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-6.6.0.pom;...
赠送jar包:lucene-queryparser-7.3.1.jar; 赠送原API文档:lucene-queryparser-7.3.1-javadoc.jar; 赠送源代码:lucene-queryparser-7.3.1-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-7.3.1.pom;...
java运行依赖jar包
资源分类:Python库 所属语言:Python 资源全名:queryparser-python2-0.2.3.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
赠送jar包:lucene-queryparser-6.6.0.jar; 赠送原API文档:lucene-queryparser-6.6.0-javadoc.jar; 赠送源代码:lucene-queryparser-6.6.0-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-6.6.0.pom;...
赠送jar包:lucene-queryparser-7.7.0.jar; 赠送原API文档:lucene-queryparser-7.7.0-javadoc.jar; 赠送源代码:lucene-queryparser-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-7.7.0.pom;...
赠送jar包:lucene-queryparser-7.2.1.jar; 赠送原API文档:lucene-queryparser-7.2.1-javadoc.jar; 赠送源代码:lucene-queryparser-7.2.1-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-7.2.1.pom;...
赠送jar包:lucene-queryparser-7.3.1.jar; 赠送原API文档:lucene-queryparser-7.3.1-javadoc.jar; 赠送源代码:lucene-queryparser-7.3.1-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-7.3.1.pom;...
赠送jar包:lucene-queryparser-7.7.0.jar; 赠送原API文档:lucene-queryparser-7.7.0-javadoc.jar; 赠送源代码:lucene-queryparser-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-7.7.0.pom;...
赠送jar包:lucene-queryparser-7.2.1.jar; 赠送原API文档:lucene-queryparser-7.2.1-javadoc.jar; 赠送源代码:lucene-queryparser-7.2.1-sources.jar; 赠送Maven依赖信息文件:lucene-queryparser-7.2.1.pom;...
java运行依赖jar包
同时,自定义的 servlet 和 QueryParser 代码可以帮助我们学习如何扩展 Solr 的核心功能,以及如何根据业务需求定制搜索引擎。 总的来说,这个开源项目为学习和实践 Solr 提供了丰富的素材,涵盖了 Solr 与 Lucene ...
lucene-queryparser-4.4.0.jar Lucene核心架包之一
lucene-queryparser-8.8.2.jar
下面将详细介绍`queryparser`的相关知识点。 首先,让我们关注PostgreSQL查询解析。PostgreSQL是一种开源的对象关系数据库管理系统,支持复杂的SQL查询语法。`queryparser`能解析PostgreSQL查询语句,将其转化为...
本篇将详细介绍Lucene的核心库以及相关组件,以帮助开发者更好地理解和使用这个功能强大的工具。 一、Lucene Core `lucene-core-5.5.0.jar` 是Lucene的核心库,包含了Lucene的基本功能。它提供了对文本进行索引和...