Rails 5.2.2中使用Thinking Sphinx多索引搜索时优先指定索引的问题
首先得拆解你遇到的核心问题:虽然文档提到后指定的索引应该优先返回,但因为你启用了RAW_ONLY中间件,跳过了Thinking Sphinx的默认结果处理逻辑,再加上Sphinx本身不会自动按照索引传入顺序来排序结果,所以才会出现index1和index2的记录混合展示的情况。另外你需要按attr分组的需求,也得和优先级逻辑结合,确保每个attr分组下优先保留index2的记录。
下面给你两个可行的解决方案:
方案一:给索引添加优先级属性,通过排序强制优先级
这个方案最贴合Sphinx的原生搜索逻辑,通过给不同索引添加专属优先级属性,让搜索结果先按优先级排序,再处理分组:
修改索引定义:
给两个索引分别添加index_priority属性,给index2设置更高的值(比如2),index1设为1:# index1的索引配置 ThinkingSphinx::Index.define Model1, with: :active_record do # 你的其他字段定义... has 1, as: :index_priority, type: :integer end # index2的索引配置 ThinkingSphinx::Index.define Model2, with: :active_record do # 你的其他字段定义... has 2, as: :index_priority, type: :integer end修改完成后,记得重新生成索引并重启Sphinx服务:
rake ts:rebuild调整查询语句:
若不是必须使用RAW_ONLY,可以去掉这个中间件,然后添加排序规则——先按index_priority降序,再按attr排序:ThinkingSphinx.search( "@attr =foo|foo*", group_by: :attr, order: "index_priority DESC, attr ASC", indices: ['index1', 'index2'] )如果必须保留
RAW_ONLY,这条语句同样适用,因为order参数会直接传递给Sphinx服务器,不会被中间件拦截。
方案二:分两次查询,手动合并结果
如果不想修改索引定义,也可以分两次分别查询两个索引,再手动合并结果,确保index2的分组结果优先展示:
# 先查询index2的分组结果 index2_results = ThinkingSphinx.search( "@attr =foo|foo*", group_by: :attr, indices: ['index2'] ) # 查询index1的分组结果,过滤掉index2中已存在的attr记录 index1_results = ThinkingSphinx.search( "@attr =foo|foo*", group_by: :attr, indices: ['index1'] ).reject { |record| index2_results.any? { |r2| r2.attr == record.attr } } # 合并结果,index2在前,index1补充在后 final_results = index2_results + index1_results
这个方案逻辑直观,不需要修改索引,适合临时需求或者索引无法调整的场景。
为什么原查询不生效?
你使用的RAW_ONLY中间件会让Thinking Sphinx直接把查询发送给Sphinx服务器,跳过了它内置的“后指定索引优先”的处理逻辑。同时Sphinx本身在多索引搜索时,默认是按照相关性排序,不会关注你传入的索引顺序,所以必须通过显式排序或者手动合并来实现你要的优先级效果。
内容的提问来源于stack exchange,提问作者H M Kashif Ali

