Solr查询实现:筛选数组字段含至少一个非指定列表值的文档
Solr多值字段存在排除列表外值的过滤实现
核心需求说明
需要筛选多值(数组类型)字段中,至少存在1个值不属于给定排除值集合的文档。示例中排除值为cat、bird,仅返回包含额外值的id=1的文档,过滤所有值均为cat/bird的文档。
前置要求
存储数组内容的字段需要配置为不分词的精确匹配类型(推荐使用Solr自带的string类型),字段属性设置multiValued="true" indexed="true";如果使用分词字段,会因为词项拆分导致匹配逻辑出错。
方案1:无需调整文档结构,原生查询直接实现(绝大多数场景适用)
直接使用字段子句内的负向匹配即可实现需求,查询语法如下:
# 基础写法,排除cat、bird两个值,匹配存在其他值的文档 q=*:*&fq=field:(* NOT "cat" NOT "bird")
逻辑说明
该查询的匹配规则为:在field字段的所有索引词项中,存在至少1个词项满足「是任意有效值、不等于cat、不等于bird」,完全匹配需求逻辑。
针对示例中的3个测试文档:
- id=1:field包含
dog,满足规则,命中返回 - id=2:field仅包含
cat/bird,无符合规则的词项,被过滤 - id=3:field仅包含
bird,无符合规则的词项,被过滤
多排除值适配
如果排除值更多,直接在括号内追加NOT "待排除值"即可,例如排除a、b、c三个值的写法为:
fq=field:(* NOT "a" NOT "b" NOT "c")
注意事项
该写法天然过滤field字段为空的文档,由于空字段不存在任何值,自然也不存在排除列表外的内容,符合绝大多数业务场景的预期,不需要额外调整。
方案2:预计算标记字段(高QPS、大数据量生产环境推荐)
如果你的文档量级在千万以上、查询QPS很高,或者排除列表固定不变,可以在文档写入阶段新增布尔类型的辅助标记字段,从根源提升查询性能:
- 新增布尔字段
has_extra_value(字段名可自定义) - 文档写入Solr时,提前判断当前文档
field字段的所有值是否全部属于排除列表:如果存在列表外的值,将该字段设为true,否则设为false - 查询时直接加过滤条件
fq=has_extra_value:true即可,性能远高于运行时拼条件查询
如果排除列表是动态变化的,不适合固定布尔字段的场景,可以开启field字段的docValues="true"属性,配合自定义SearchComponent或Streaming Expression实现高效过滤,避免全索引扫描。
兜底兼容方案(老版本Solr适配)
如果你使用的是4.0以下的老版本Solr,不支持上述字段内负向匹配的写法,可以使用函数查询实现等价逻辑,通过对比字段总元素数和匹配排除值的元素数判断是否存在额外值:
fq=*:* -_query_:"{!func}eq(fieldValueCount(field), sum(if(query({!v='field:cat'}),1,0), if(query({!v='field:bird'}),1,0)))"
该写法逻辑为:统计字段总长度,再统计字段中匹配排除值的元素个数,如果两个数值相等,说明所有值都在排除列表内,将这类文档过滤即可。如果排除值更多,在sum函数内追加对应if(query({!v='field:待排除值'}),1,0)片段即可。
内容的提问来源于stack exchange,提问作者Thomas Guillot
相关产品推荐
相关产品推荐

