Solr布尔查询的使用实践

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
简介: Solr支持类似布尔语法的查询,使用AND、OR、&&、!、+、-符号,但是在使用过程中会有一些难以理解的地方,本文主要拿一个例子来介绍如何正确的使用布尔查询。

前言

Solr支持布尔查询,使用AND、OR、&&、!、+、-符号,具体可参考社区的文档介绍

但是,在使用过程中,可能有些查询的结果会引起困扰,需要深入理解Lucene的boolean查询规则。本文就拿具体的例子介绍如何理解其中的规则。

规则

布尔查询在代码中主要有下面四种标识,BooleanClause.java。

  • MUST,用+标识
  • SHOULD,用空字符标识
  • MUST_NOT,用-标识
  • FILTER(不常用,先忽略)

结果按照下面规则返回。
1.MUST和MUST:取得连个查询子句的交集。
2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。
3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。
4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。
6.MUST_NOT和MUST_NOT:无意义,检索无结果。

在使用布尔查询时,最容易引起误解的是-语法,因此,下面的例子主要讲述-的使用。其它语法的使用和普通的布尔逻辑语义类似。

举例

在使用Solr查询时,如何确定布尔查询的符号,可以通过debugQeury获取到parsedquery_toString。
写入四条数据:
id,update_version_l,name_s,age_i
1,1,zhangsan,10
2,2,lisi,10
3,3,wangwu,20
4,4,zhaoliu,10

solr_docs.png

  • 示例1
age_i:10 OR -name_s:zhangsan   
#找到age_i等于10的数据,或者name_s不等于zhangsan的数据。按照正常布尔逻辑的理解,应该返回4条数据,但实际查询只返回2条数据

query1.png

编译后的语法是

age_i:[10 TO 10] -name_s:zhangsan

代表的是SHOULD和MUST_NOT的组合,参照规则3。

序号 查询条件 命中的id
1 age_i:[10 TO 10] 1,2,4
2 name_s:zhangsan 1

按照规则3:首先拿到序号1条件的结果,再排除序号2条件的结果,也就是最终结果为2, 4。

  • 示例2
age_i:10 OR (-name_s:zhangsan)
#业务要达到的目的和示例1一致,期望返回4条数据,但实际结果返回3条数据。

query2.png

编译后的语法

age_i:[10 TO 10](-name_s:zhangsan)

注意到这里(-name_s:zhangsan)代表的是MUST NOT,实际意义是文档集中不应该有name_s:zhangsan的数据,但实际是有的,因此这个子查询返回0条数据。
参考规则5。

序号 查询条件 命中的id
1 age_i:[10 TO 10] 1,2,4
2 (-name_s:zhangsan) NA

按照规则5,两个结果取并集,最终结果就是1,2,4

  • 示例3
age_i:10 AND -name_s:zhangsan
#找到age_i:10的数据,并且name_s不等于zhangsan,理论应该返回2条数据,实际结果也是符合预期。

query3.png

  • 示例4
id:("1" "2" "3" "4") AND (-name_s:zhangsan OR age_i:10)

query4.png

编译后的语法是

+(id:1 id:2 id:3 id:4) +(-name_s:a age_i:[10 TO 10])

代表的是 MUST和MUST(MUST_NOT和SHOULD的组合)的组合

name_s:a => 1
age_i:[10 TO 10] => 1, 2, 4
(-name_s:a age_i:[10 TO 10]) => 2, 4
(id:1 id:2 id:3 id:4) => 1, 2, 3, 4
+(id:1 id:2 id:3 id:4) +(-name_s:a age_i:[10 TO 10]) => 2, 4

最疑惑的-符号如何解?

当使用-语法时,主动用*:*来和-组成一个AND语法。
即:
-name_s:zhangsan
转换为如下写法
(*:* AND -name_s:zhangsan)
那么,我们来回顾上面的三个例子:

  • 示例1
age_i:10 OR -name_s:zhangsan  

改成如下写法,结果符合预期。

age_i:10 OR (*:* AND -name_s:zhangsan)
  • 示例2
age_i:10 OR (-name_s:zhangsan)

改成如下写法,结果符合预期。

age_i:10 OR (*:* AND -name_s:zhangsan)
  • 示例3
age_i:10 AND -name_s:zhangsan

改成如下写法,结果仍然符合预期

age_i:10 AND (*:* AND -name_s:zhangsan)
  • 示例4
id:("1" "2" "3" "4") AND (-name_s:zhangsan OR age_i:10)

改成如下写法,结果符合预期

id:("1" "2" "3" "4") AND ((*:* AND -name_s:zhangsan) OR age_i:10)

参考文档

https://lucidworks.com/post/why-not-and-or-and-not/

目录
相关文章
|
JSON 自然语言处理 数据格式
分布式系列教程(33) -ElasticSearch DSL语言查询与过滤
分布式系列教程(33) -ElasticSearch DSL语言查询与过滤
204 0
|
7月前
|
存储 缓存 Java
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
202 0
|
存储 SQL 缓存
|
存储 SQL 缓存
四.全文检索ElasticSearch经典入门-字符串查询&批量查询&DSL查询过滤&乐观锁
四.全文检索ElasticSearch经典入门-字符串查询&批量查询&DSL查询过滤&乐观锁
|
7月前
|
关系型数据库 分布式数据库 PolarDB
使用 PolarDB 开源版 bloom filter index 实现任意字段组合条件过滤
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍使用 PolarDB 开源版 bloom filter index 实现任...
140 0
|
存储 SQL 并行计算
使用 PolarDB 开源版 bloom filter index 实现任意字段组合条件过滤
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍使用 PolarDB 开源版 bloom filter index 实现任意字段组合条件过滤
276 0
|
Apache 数据格式 算法
|
存储 搜索推荐 Java
搜索引擎solr中string类型字段排序混乱问题
elasticsearch与solr作为目前市面上主流的搜索引擎可以满足绝大多数搜索场景,伴随着搜索而来的就是排序。下面记录一次solr中string类型字段排序混乱问题。
556 0
搜索引擎solr中string类型字段排序混乱问题
|
自然语言处理 索引
Elasticsearch 如何实现查询/聚合不区分大小写?
1、实战问题 最近社区里有多个关于区分大小写的问题: 问题1:ES查询和聚合怎么设置不区分大小写呢? 问题2:ES7.6 如何实现模糊查询不区分大小写? 主要是如何进行分词和mapping的一些设置来实现这个效果, 自己也尝试过对setting 和 mapping字段进行设置,都是报错比较着急, 类似的问题,既然有很多同学问到,那么咱们就有必要梳理出完整的思路和方案。 这或许是铭毅天下公众号的使命所在。 这个问题不复杂,所以本文会言简意赅,直击要害!
869 0
Elasticsearch 如何实现查询/聚合不区分大小写?
|
存储 数据建模 Java
干货 | 拆解一个 Elasticsearch Nested 类型复杂查询问题
1、线上实战问题 前置说明:本文是线上环境的实战问题拆解,涉及复杂 DSL,看着会很长,但强烈建议您耐心读完。
717 0
干货 | 拆解一个 Elasticsearch Nested 类型复杂查询问题