如何在Solr中跳过文本搜索仅传递用户信息用于自定义排序?
我之前也碰到过一模一样的需求,其实核心就是把用户信息和搜索查询拆分开——别把用户数据塞到q参数里,而是用自定义请求参数单独传递,同时让Solr只执行你需要的排序逻辑,不把用户信息当作文本关键词去匹配。下面是具体的实现方案和代码示例:
核心思路
- 用自定义请求参数(比如
user_info)传递用户的31,1这类数据,彻底避免和搜索关键词混淆 - 将搜索的
q参数设为*:*(如果不需要过滤文档),或者保留你原本的过滤条件,只把用户信息从q里剥离 - 在自定义的
CustomScoreProvider中读取这个自定义参数,用于计算排序得分
代码实现示例
1. 自定义ScoreProvider和QParserPlugin
首先需要一个自定义的QParserPlugin来创建你的CustomScoreProvider,这样才能在解析查询时获取请求参数:
import org.apache.solr.common.params.SolrParams; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.search.QParser; import org.apache.solr.search.QParserPlugin; import org.apache.solr.search.SyntaxError; import org.apache.solr.search.function.CustomScoreProvider; import org.apache.solr.search.function.CustomScoreQuery; public class UserAwareScorePlugin extends QParserPlugin { @Override public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { return new QParser(qstr, localParams, params, req) { @Override public org.apache.solr.search.Query parse() throws SyntaxError { // 获取自定义的用户信息参数并解析 String userInfo = getParams().get("user_info"); String[] userData = userInfo.split(","); int userId = Integer.parseInt(userData[0]); int userType = Integer.parseInt(userData[1]); // 这里用MatchAllDocsQuery匹配所有文档,如果你有原本的过滤条件,替换成你的baseQuery即可 org.apache.solr.search.Query baseQuery = new org.apache.solr.search.MatchAllDocsQuery(); return new CustomScoreQuery(baseQuery) { @Override protected CustomScoreProvider getCustomScoreProvider(SolrQueryRequest req) { return new CustomScoreProvider(req) { @Override public float customScore(int doc, float subQueryScore, float[] valSrcScores) { // 这里根据userId和userType计算自定义得分 float score = subQueryScore; if (userType == 1) { // 示例:从文档中读取关联字段,结合用户信息调整得分 float userRelevance = req.getSearcher().doc(doc).getFloatValue("user_relevance"); score += userRelevance * userId * 0.1f; } return score; } }; } }; } }; } }
2. 在solrconfig.xml中注册插件
把你的自定义插件注册到Solr配置文件里:
<queryParser name="user_aware_score" class="com.yourpackage.UserAwareScorePlugin"/>
3. 发起查询请求
现在可以用这个插件发起查询,用户信息通过user_info参数传递,q参数用*:*(或你的过滤条件):
GET /solr/your_core/select?defType=user_aware_score&q=*:*&user_info=31,1&sort=score desc
如果需要保留原本的过滤条件(比如只搜索分类为electronics的文档):
GET /solr/your_core/select?defType=user_aware_score&q=category:electronics&user_info=31,1&sort=score desc
轻量替代方案:用Function Query传递参数
如果不想写复杂的QParserPlugin,也可以用Solr的Function Query结合param()函数传递参数,在bf(Boost Function)中使用:
1. 自定义ValueSource函数
import org.apache.solr.search.ValueSource; import org.apache.solr.search.function.ValueSourceParser; import org.apache.solr.search.function.FloatValueSource; import org.apache.solr.common.params.SolrParams; public class UserBonusValueSourceParser extends ValueSourceParser { @Override public ValueSource parse(FunctionQParser fp) throws SyntaxError { // 直接从请求参数中获取用户信息 int userId = fp.getIntParam("user_id"); int userType = fp.getIntParam("user_type"); return new FloatValueSource() { @Override public float floatVal(int doc) { // 根据用户信息计算加分 return userType == 1 ? userId * 0.1f : 0f; } @Override public String description() { return "user_bonus(" + userId + "," + userType + ")"; } }; } }
2. 注册函数到solrconfig.xml
<valueSourceParser name="user_bonus" class="com.yourpackage.UserBonusValueSourceParser"/>
3. 发起查询
GET /solr/your_core/select?q=*:*&bf=user_bonus()&user_id=31&user_type=1&sort=score desc
内容的提问来源于stack exchange,提问作者Quiz Master
相关产品推荐
相关产品推荐

