nested doc,是solr提供的一种父子文档嵌套的结构,但是由于在lucene中,所有文档的存储都是扁平结构的,所以嵌套只是逻辑上的说法,在物理存储中,父子嵌套是根据所有相关联的父子文档紧密排列,并且按照 子->子->父 的顺序排序,每个区块都必须父作为结尾。
如何添加nested doc结构的索引?
直接上代码
SolrInputDocument doc = new SolrInputDocument();
doc.setField("id",1);
doc.setField("author","D'angelo");
doc.setField("type","p");
SolrInputDocument c = new SolrInputDocument();
c.setField("id",2);
c.setField("title","solr in action");
c.setField("comments","bravo");
c.setField("type","c");
//**将c添加为doc的子文档*/
doc.addChildDocument(c);
SolrInputDocument doc2 = new SolrInputDocument();
doc2.setField("id",3);
doc2.setField("author","Russell");
doc2.setField("type","p");
SolrInputDocument c2 = new SolrInputDocument();
c2.setField("id",4);
c2.setField("title","java in action");
c2.setField("comments","good");
c2.setField("type","c");
doc2.addChildDocument(c2);
则在solr查询时,我们可以利用{!parent}的queryParser查询方法,来通过子文档的属性来反查父文档,
/**Usage: {!parent which="PARENT:true"}CHILD_PRICE:10*/
query:
{!parent
which=type:p}title:"java in action"
"response": {
"numFound": 1,
"start": 0,
"docs": [
{
"id": "3",
"author": "Russell",
"author_s": "Russell",
"type": "p",
"_version_": 1601161242996637700,
"_root_": "3",
"_childDocuments_": [
{
"id": "4",
"title": "java in action",
"comments": "good",
"type": "c",
"_root_": "3"
}
]
}
]
}
若想同时得到父子文档,则设置
fl:*,[child parentFilter=type:p]
以上就是nested doc查询的基本应用,下面介绍一下在近期工作中用到nested doc的一些稍微复杂一点的操作。
业务需求
目前有一批顾客信息和商店信息的一对多关系的数据,顾客信息包括该顾客历史吃过的所有的菜,商店信息为商店的坐标点以及该顾客在该商店中的吃过的菜
基于以上数据,业务方想要通过两个查询条件,得到满足要求的顾客
- 1:顾客以前吃过某几个特定的菜
- 2:顾客曾光临过给定坐标点的附近某个距离范围内的店铺
基于业务需求,很明显需要用到上面介绍的nested doc的结构,
但是如何查询得到我们想要的结果呢,很明显要借鉴{!parent}的查询方式
所以先看一下这个queryParser的源代码
public class BlockJoinParentQParserPlugin extends QParserPlugin {
public static final String NAME = "parent";
@Override
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
QParser parser = createBJQParser(qstr, localParams, params, req);
return parser;
}
protected QParser createBJQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
return new BlockJoinParentQParser(qstr, localParams, params, req);
}
}
发现真正起作用的是返回的BlockJoinParentQParser,再看一下这个的源代码
protected String getParentFilterLocalParamName() {
return "which";
}
BlockJoinParentQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
super(qstr, localParams, params, req);
}
public Query parse() throws SyntaxError {
String filter = this.localParams.get(this.getParentFilterLocalParamName());
String scoreMode = this.localParams.get("score", ScoreMode.None.name());
QParser parentParser = this.subQuery(filter, (String)null);
Query parentQ = parentParser.getQuery();
String queryText = this.localParams.get("v");
if(queryText != null && queryText.length() != 0) {
QParser childrenParser = this.subQuery(queryText, (String)null);
Query childrenQuery = childrenParser.getQuery();
return this.createQuery(parentQ, childrenQuery, scoreMode);
} else {
SolrConstantScoreQuery wrapped = new SolrConstantScoreQuery(this.getFilter(parentQ));
wrapped.setCache(false);
return wrapped;
}
}
protected Query createQuery(Query parentList, Query query, String scoreMode) throws SyntaxError {
//AllParentsAware extends ToParentBlockJoinQuery
return new BlockJoinParentQParser.AllParentsAware(query, this.getFilter(parentList).filter, ScoreModeParser.parse(scoreMode), parentList);
}
也就是将which后的语句解析为parentFilter(下方红色部分),将{}外的语句解析为childQuery(下方蓝色部分)
{!parent which="PARENT:true"}CHILD_PRICE:10
再拼装成ToParentBlockJoinQuery的一个Query类型,具体查询时先用parentFilter定位到满足条件的父文档,再根据父子文档物理位置相邻的特性,直接向上移动指针,遍历其子文档,再根据childQuery筛选我们需要的子文档
所以根据我们上述的两个需求,将第一点封装成parentFilter,将第二点封装成childQuery即可,这里的细节不细说了,直接说结果
1:{!terms f=sfield}A,B,C 用于获取吃过ABC三个菜其中之一的客户
2:{!geofilt sfield=coordinate pt=X,Y d=10} 用于获取满足经纬度X,Y范围10km内的店铺
但是如果直接拼装成如下的语句,在解析时会出现问题,因为中间的空格都会被当做分隔符分开,造成语句的错乱
{!parent which={!terms f=sfield}A,B,C}{!geofilt sfield=coordinate pt=X,Y d=10}
为了解决这个问题,自己定义一个queryParser,继承BlockJoinParentQParserPlugin,改写其中的createParser方法,
//UserRecommendParentQPlugin extends BlockJoinParentQParserPlugin
@Override
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
String sfield = localParams.get("sfield","coordinate");
String pt = localParams.get("pt", "0.0,0.0");
String d = localParams.get("d", "100");
String terms = localParams.get("termList","");
String parentQ = "{!terms f=termcount}"+term
String q = "{!geofilt sfield="+sfield+" pt="+ pt+" d="+d+"}";
logger.info("child query: "+ q);
if(localParams instanceof ModifiableSolrParams){
((ModifiableSolrParams) localParams).set("which","type:p");
((ModifiableSolrParams) localParams).set("v",q);
}
QParser parser = createBJQParser(q, localParams, params, req);
return parser;
}
即自己在解析时传入拼好的值,则能有效的避免这个问题,在查询时也就只用传入我们需要后续拼接的参数即可
{!userRecommend sfield=xxx pt=xxx d=xxx termList=xxx }userId:123
这样就解决了我们的需求
Problem Solved!
分享到:
相关推荐
本教程将深入探讨Solr的基本概念、安装配置、索引管理、查询操作以及solrJ库的使用,同时也涉及到了IK分词器的详细应用。 首先,让我们了解一下Solr的核心概念。Solr是基于Lucene的搜索服务器,它可以快速地处理...
### Solr 3.5配置及应用知识点详解 #### 一、Solr简介 - **定义**:Apache Solr是一款高性能、开源的搜索服务器。它使用Java语言开发,并且主要基于HTTP协议和Apache Lucene技术实现。 - **数据模型**:在Solr中,...
solr7.5官方文档是pdf格式,经本人转换成doc,可供阅读参考
### Solr开发详解 #### Solr简介 - **Solr** 是 Apache 软件基金会旗下的顶级开源项目之一,它是一款高性能的全文检索服务器。Solr 基于 Java 开发,利用 Lucene 作为其核心搜索引擎库。 - **特点**: - 可扩展性...
本文将深入探讨Solr的主要功能,包括环境搭建、配置、索引维护、查询及各种高级功能的实现。 1. Solr基础 Solr是一款由Java编写的搜索引擎,其核心功能包括层面搜索、高亮显示、拼写检查、搜索建议、分组统计、...
- 在 Tomcat 的 `conf/server.xml` 文件中添加一个新的 `<Host>` 或 `<Context>` 元素,指定 Solr 的应用上下文路径,如 `<Context path="/solr" docBase="solr" />`。 - 启动或重启 Tomcat 服务,Solr 应该可以...
资源名称:相关性搜索 利用Solr与Elasticsearch创建智能应用内容简介:《相关性搜索:利用Solr与Elasticsearch创建智能应用》揭开了相关性搜索的神秘面纱,告诉大家如何将 Elasticsearch与 Solr这样的搜索引擎作为可...
在3.5版本中,Solr 已经成为一个成熟的技术,广泛应用于网站的全文检索、商品搜索、文档检索等多个场景。本文将深入探讨 Solr 3.5 的配置及其在实际应用中的关键点。 首先,配置 Solr 3.5 包括以下几个主要步骤: ...
Solr是Apache软件基金会的一个开源项目,是一款强大的全文搜索引擎,被广泛应用于企业级搜索解决方案。在本教程中,我们将深入探讨Solr 3.5版本的开发应用,重点关注其实战应用,以帮助开发者更好地理解和利用这个...
**SOLR应用教程** **一、概述** 1.1 企业搜索引擎方案选型 在为企业选择搜索引擎解决方案时,需要考虑的关键因素包括处理能力、可扩展性、易用性、性能以及对特定业务需求的支持。Solr作为一种开源的企业级搜索...
for (SolrDocument doc : results) { // 处理每个搜索结果 } client.close(); ``` 此外,Solr还支持实时更新,这意味着当我们有新的数据需要添加或现有数据需要修改时,可以直接调用相应的API,而无需重新构建整个...
在本篇中,我们将深入探讨Solr 7.7.3的配置细节,并了解如何将其与Spring Boot 2.x进行整合,构建一个高效、可扩展的搜索引擎应用。 **一、Solr 7.7.3核心配置** 1. **安装与启动** - 首先,你需要下载Solr 7.7.3...
Apache Solr 7.5是Apache Lucene项目的一个开源...总的来说,Apache Solr 7.5官方文档是开发人员、系统管理员和数据分析师必备的参考资料,无论选择PDF还是DOC格式,都能帮助读者深入理解并充分利用Solr的强大功能。
通过以上步骤,我们可以成功地部署Solr并在Java应用程序中使用SolrJ进行数据索引和搜索。Solr的强大功能和灵活性使其成为构建高效搜索系统的一个优秀选择。无论是对于企业级应用还是个人项目,Solr都是一个值得深入...
本文将详细介绍 SpringBoot 整合 Solr 的方法详解,并提供示例代码,以便读者更好地理解和应用。 SpringBoot 整合 Solr 的必要配置 要整合 Solr,首先需要添加 Solr 依赖项到 Maven 项目中: ```xml <groupId>...
【开源企业搜索引擎Solr的应用教程】 企业搜索引擎是现代数字化企业不可或缺的一部分,它们为用户提供高效、准确的信息检索体验。在各种搜索引擎方案中,Apache Solr因其强大的功能和优秀的可扩展性,已经成为众多...