elasticsearch干货:使用FunctionScore对文档进行从新打分实例

直接上代码!
{
  "function_score" : {
    "query" : {
      "bool" : {
        "must" : [
          {
            "term" : {
              "mediaType" : {
                "value" : 2,
                "boost" : 1.0
              }
            }
          },
          {
            "term" : {
              "status" : {
                "value" : 1,
                "boost" : 1.0
              }
            }
          }
        ],
        "adjust_pure_negative" : true,
        "boost" : 1.0
      }
    },
    "functions" : [
      {
        "filter" : {
          "match_all" : {
            "boost" : 1.0
          }
        },
        "script_score" : {
          "script" : {
            "source" : "(doc['countRead'].value+doc['countLike'].value+doc['countComment'].value)/3",          
            "lang" : "painless"
          }
        }
      }
    ],
    "score_mode" : "multiply",
    "boost_mode" : "multiply",
    "max_boost" : 3.4028235E38,
    "boost" : 1.0
  }
} 

"source" : "(doc['countRead'].value+doc['countLike'].value+doc['countComment'].value)/3", 
//表示以字段“countRead”,“countLike”,“countComment” 的平均值为新的分数

spring data es的代码实现以下:git

NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(QueryBuilders.termQuery("mediaType", ServiceConstant.MEDIA_VEDIO))
        .must(QueryBuilders.termQuery("status", ServiceConstant.ARTICLE_STATUS_PUBLISHED));
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder,ScoreFunctionBuilders.scriptFunction(
        new Script("(doc['countRead'].value+doc['countLike'].value+doc['countComment'].value)/3")))
        .scoreMode(FunctionScoreQuery.ScoreMode.MULTIPLY)
        .boostMode(FunctionScoreQueryBuilder.DEFAULT_BOOST_MODE);
System.out.println(functionScoreQueryBuilder);
nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder)
        .withPageable(PageRequest.of(PageUtil.getPage(param.getPage()) - 1, PageUtil.getPageSize(param.getPage_size())));
Page<ArticleEs> articlePage = articleEsRepository.search(nativeSearchQueryBuilder.build());

解析:functionScoreQuery由queryBuilder(业务查询)和scriptFunction(自定义打分脚本)两部分组成(上图黄色部分),再把functionScoreQuery放入nativeSearchQueryBuilder中添加一些分页参数便可(上面蓝绿色部分);spring

参考资料:FunctionScoreless

10/16:最近根据业务写搜索接口,要根据用户位置信息,商品发布时间,评分,是否推荐这几个属性综合排序,也就是说要用不一样的函数对文档从新打分:函数

{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },//这里是业务搜索语句
      "functions": [
        {
          "filter": {
            "term": {
              "recommended": "1"
            }
          },
          "weight": 2
        },//这里表示:若是是推荐商品则权重设置为2
        {
          "gauss": {
            "location": {
              "origin": {
                "lat": 23.0932922,
                "lon": 113.4052734
              },
              "offset": "10km",
              "scale": "1km"
            }
          },
          "weight": 3
        },//这里的高斯函数表示:以origin点为中心,offset为半径的范围内的为最佳匹配结果,每超过scale公里配分就降低
        {
          "linear": {
            "score": {
              "origin": 8.5,
              "offset": 1.5,
              "scale": 2
            }
          },
          "weight": 2
     },//这里linear函数和guass函数相似(只是曲线不一样而已)以8.5为圆点,上下1.5分的范围也就是7-10分为最佳匹配,每低于2分降低(score为es字段,表示商品分)
        {
          "gauss": {
            "createTime": {
              "origin": "2019-10-15T10:24:32+08:00",
              "offset": "5d",
              "scale": "5d"
            }
          },
          "weight": 2
        }//以origin这个时间点为中心,先后五天的范围内为最佳,没超过5天评分就降低
      ],
      "score_mode": "sum",                //score_mode表示对上面几个函数处理得出的子分数如何处理,这里是相加得出一个总分数;
      "boost_mode": "multiply"            //boost_mode表示上一步得出的总分数与原分数之间如何处理,这里是两个分数相乘获得最后一个分数
    }
  }
}

data es 代码以下ui

//构造FunctionScore
private FunctionScoreQueryBuilder  getFilterFunctionBuilders(BoolQueryBuilder boolQueryBuilder,Double latitude,Double longitude){
    FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[4];
    //filter打分
    FunctionScoreQueryBuilder.FilterFunctionBuilder filterFunctionBuilder=new     FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("recommended", 1),new WeightBuilder().setWeight(2));
    filterFunctionBuilders[0]=filterFunctionBuilder;
    //距离打分
    Map locationMap=new HashMap();
    locationMap.put("lat",latitude);
    locationMap.put("lon",longitude);
    GaussDecayFunctionBuilder distanceGaussDecayFunctionBuilder=ScoreFunctionBuilders
            .gaussDecayFunction("location",locationMap, "1km", "5km").setWeight(3);
    filterFunctionBuilders[1]=new FunctionScoreQueryBuilder.FilterFunctionBuilder(distanceGaussDecayFunctionBuilder);
    //评分打分
    LinearDecayFunctionBuilder ScoreLinearDecayFunctionBuilder=ScoreFunctionBuilders.linearDecayFunction("score", 8.5, 1, 1.5).setWeight(2);
    filterFunctionBuilders[2]=new FunctionScoreQueryBuilder.FilterFunctionBuilder(ScoreLinearDecayFunctionBuilder);
    //日期打分
    GaussDecayFunctionBuilder dateGaussDecayFunctionBuilder=ScoreFunctionBuilders.gaussDecayFunction("createTime", new Date(), "5d", "5d").setWeight(2);
    filterFunctionBuilders[3]=new FunctionScoreQueryBuilder.FilterFunctionBuilder(dateGaussDecayFunctionBuilder);
    FunctionScoreQueryBuilder functionScoreQueryBuilder= QueryBuilders.functionScoreQuery(boolQueryBuilder,filterFunctionBuilders)
            .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
            .boostMode(CombineFunction.SUM);
    return functionScoreQueryBuilder;
} //最后构造完FunctionScore须要放入NativeSearchQueryBuilder中,参数boolQueryBuilder为其它的一些业务查询条件