Solr多值字段查询逻辑问题求助
看起来你是碰到了Solr里关联多值字段的典型问题——你的type.id、type.demande这些多值字段是按位置绑定成组的(比如type.id[0]和type.demande[0]属于同一组属性),但Solr默认的多值查询会跨组匹配(比如可能把某一组的type.demande:oui和另一组的type.traitement:non凑在一起匹配),这显然不是你想要的结果。
下面给你两种解决方案,优先推荐第一种,是Solr处理这类场景的标准做法:
方案一:嵌套子文档+Block Join查询(最可靠)
把每组type属性拆成独立的子文档,这样就能精准查询包含符合条件子组的父文档。
1. 重构你的索引结构
把原来的平行多值字段改成嵌套子文档,每组type数据作为父文档的子节点:
"docs": [ { "id":"doc1", "_childDocuments_": [ { "type.id": "1", "type.demande": "non", "type.reponse": "oui", "type.traitement": "oui", "is_type_child": true }, { "type.id": "2", "type.demande": "non", "type.reponse": "oui", "type.traitement": "oui", "is_type_child": true }, { "type.id": "3", "type.demande": "oui", "type.reponse": "", "type.traitement": "non", "is_type_child": true } ] }, { "id":"doc2", "_childDocuments_": [ { "type.id": "1", "type.demande": "non", "type.reponse": "oui", "type.traitement": "oui", "is_type_child": true }, { "type.id": "2", "type.demande": "non", "type.reponse": "oui", "type.traitement": "oui", "is_type_child": true }, { "type.id": "3", "type.demande": "non", "type.reponse": "non", "type.traitement": "", "is_type_child": true } ] } ]
这里加了is_type_child布尔字段,用来标记子文档,方便后续区分父/子文档。
2. 配置Schema
确保你的Schema里有这些配置:
- 子文档用到的字段(
type.id、type.demande等),根据需求设置合适的类型(比如string就够用,不需要分词的话) - 新增
is_type_child字段:
<field name="is_type_child" type="boolean" indexed="true" stored="true"/>
3. 执行目标查询
比如你要找存在一组type.demande:oui且type.traitement:non的文档(也就是doc1),用Block Join的查询语法:
q={!parent which="is_type_child:false"}type.demande:oui AND type.traitement:non
which="is_type_child:false":指定父文档的筛选规则(父文档没有这个字段或者值为false)- 括号里的内容:匹配满足条件的子文档,最终返回的是包含这类子文档的父文档。
方案二:位置约束(临时应急,不推荐长期用)
如果暂时没法重构索引,可以利用多值字段的位置对应关系,用位置增量来强制条件在同一组。但这个方法依赖索引时的字段顺序,一旦顺序变了就失效,只能临时用用。
比如查询同一组内type.demande:oui且type.traitement:non的文档:
q=*:*&fq={!edismax qf="type.demande type.traitement" pf="type.demande type.traitement^100"}"oui non"&fq=type.demande:oui&fq=type.traitement:non
这里通过短语查询结合位置权重,强制两个值出现在同一位置,从而保证是同一组的属性。
总结
优先选嵌套子文档+Block Join的方案,逻辑清晰、可靠性高,是Solr处理关联多值场景的标准做法。位置约束只适合临时救急,别长期用。
内容的提问来源于stack exchange,提问作者Guillaume G.

