冬天温泉的小庭院

solr 中非或查询的 magic

提问:在 solr 中进行非查询的 query 是写作 -field:value,或查询的 query 是写作 field:value1 OR field:value2,那么,对同一字段进行多次非或的查询应该如何写呢?

……

从直觉上来说应该是写作 -field:value1 OR -field:value2 ,这么是没问题并且也是可以检索出数据的,但是如果加上其他的条件比如 (-field:value1 OR -field:value2) AND other_or_some_field:value3 这样的话,这样是检索不出来数据的,why??

原因请看 Negative Query Problems 这个 solr 官方的 wiki,上面说这是『Solr Magic』哦,而不是个 bug 哦,好吧。。。

解决方法:多查询条件下,在非查询的前面添加全量查询即可,即 ((*:* AND -field:value1) OR (*:* AND -field:value2)) AND other_field:value3。而 (-field:value1 OR -field:value2) 这个条件跟 -(field:value1 AND field:value2) 其实是等效的逻辑,所以进一步可改写成 (*:* AND -(field:value1 AND field:value2)) AND other_field:value3。也就是说,多条件的情况下,非或条件要写成 (*:* AND -field:value) 这样的形式,并且如果可以的话尽量把非或条件写到最后以避免出现这个 magic。

如果情况允许的话,可以把查询条件用 fq 来进行查询。

……

然后就是,如果用到了 spring-data-solr 来进行 solr 查询的话,(*:* AND -field:value) 的写法如下

1
2
Criteria criteria = Criteria.where(field).is(value);
criteria = Criteria.where(Criteria.WILDCARD).expression(Criteria.WILDCARD).and(criteria.notOperator()).connect();

也就是说,先用 notOperator() 方法给 criteria 用 -() 给包起来,然后跟 *:* 与结合之后,用 connect() 方法把该次查询加上括号。最后加上括号是为了跟其他条件进行拼接,这对括号的本身并不影响查询。

然后就是多个条件的非或查询比如 (*:* AND -(field:value1 AND field:value2)) 的写法如下

1
2
3
Criteria criteria = Criteria.where(field).is(value1);
criteria = criteria.and(Criteria.where(field).is(value2));
criteria = Criteria.where(Criteria.WILDCARD).expression(Criteria.WILDCARD).and(criteria.notOperator()).connect();

This’s “Solr Magic” with negative queries。