Elasticsearch 实战:基于 function_score 的搜索与权重排序

Elasticsearch 实战:基于 function_score 的搜索与权重排序

    下面基于项目中关于律师笔记的es搜索功能开发,来记录下es中基于 function_score 的搜索与权重排序在项目中是如何具体应用和实现的。

    一、需求内容

    项目中有一个功能,简单描述为:全局搜索公开展示的律师笔记,通过输入关键词,匹配笔记标题,律师姓名、律所名称、擅长领域这四个字段,排序规则:点赞数 (由高到低)> 笔记发布时间(由近到远)> 笔记ID(由大到小)

    可以理解为:

    搜索内容涉及:笔记标题(title 字段),作为最核心的匹配字段。

    律师信息,包括律师姓名(nick_name)、律所名称(law_firm)和擅长领域(good_at_topic)。这些字段也会影响匹配度,但权重较标题低。

    排序优先级:

    第一优先级: 根据笔记的“点赞数”(like_count)倒序排列,点赞越多,排序越靠前。

    第二优先级: 在点赞数相同时,按笔记的“发布时间”(create_time)倒序排列,最新发布的笔记优先展示。

    兜底排序规则:若上述条件均相同,则按 id 主键倒序排序。

   二、需求分析

   1.  擅长领域存入es的是id 数组,需要先通过分词到主题 topic 索引中查询 匹配的id数组,再去笔记 note 索引中做笔记查询

   2.  使用 function_score 来给不同匹配条件设置不同权重,提高匹配精准度。( 搜索字段的权重从高到低:标题 > 律师姓名 > 律所名称 > 擅长领域

   3.  通过 Elasticsearch 自带的排序机制,实现基于 like_count、create_time 和 id 的多级排序。

   4.  利用 filter 确保部分条件不影响打分,只作为过滤条件(例如笔记状态必须为公开)。

   三、Java代码实现

   技术背景:java 框架使用springboot 2.6, elasticsearch 8.15,es框架使用的是 easy-es 3.0.0 

   部分重要代码示例:

   四、DSL查询示例

   笔记 note 索引的Mapping定义:

PUT /note
{
   "settings": {
    "number_of_shards": 7,
    "index.max_ngram_diff": 2,
    "analysis": {
      "tokenizer": {
        "ik_smart_tokenizer": {
          "type": "ik_smart"
        },
        "ngram_tokenizer": {
          "type": "ngram",
          "min_gram": 2,
          "max_gram": 3
        }
      },
      "filter": {
        "ngram_filter": {
          "type": "ngram",
          "min_gram": 2,
          "max_gram": 3
        }
      },
      "analyzer": {
        "ik_ngram_analyzer": {
          "type": "custom",
          "tokenizer": "ik_smart_tokenizer",
          "filter": ["ngram_filter"]
        },
        "ngram_analyzer": {
          "type": "custom",
          "tokenizer": "ngram_tokenizer"
        }
      }
    }
  },
  "aliases": {
    "note_alias": {}
  },
  "mappings": {
    "properties": {
      "id": { "type": "keyword" },
      "lawyer_id": { "type": "keyword" },
      "name": { "type": "keyword"},
      "nick_name": { "type": "keyword"},
      "law_firm": { "type": "keyword"},
      "good_at_topic": { "type": "keyword" },
      "head_url": { "type": "keyword" },
      "title": { 
        "type": "text", 
        "analyzer": "ik_ngram_analyzer", 
        "fields": { 
          "keyword": { 
            "type": "keyword", 
            "ignore_above": 256 
          } 
        }
      },
      "cover": { "type": "keyword" },
      "description": { "type": "keyword"},
      "type": { "type": "keyword" },
      "content": { "type": "keyword" },
      "status": { "type": "keyword" },
      "top": { "type": "integer" },
      "top_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" },
      "like_count": { "type": "integer" },
      "comment_count": { "type": "integer" },
      "collect_count": { "type": "integer" },
      "share_count": { "type": "integer" },
      "look_count": { "type": "integer" },
      "create_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" },
      "create_by": { "type": "keyword" },
      "update_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" },
      "update_by": { "type": "keyword" },
      "version": { "type": "keyword" }
    }
  }
}

   查询DSL语句为:

GET /note/_search
{
  "from": 0,
  "query": {
    "bool": {
      "filter": [  // 不参与评分
        {
          "bool": {
            "must": [
              {
                "term": {
                  "status": {
                    "boost": 1,
                    "value": "PUBLIC"
                  }
                }
              }
            ]
          }
        }
      ],
      "must": [
        {
          "function_score": {
            "boost_mode": "multiply",
            "functions": [
              {
                "filter": {
                  "match": {
                    "title": {
                      "query": "测试"
                    }
                  }
                },
                "weight": 10000
              },
              {
                "filter": {
                  "wildcard": {
                    "nick_name": {
                      "value": "*测试*"
                    }
                  }
                },
                "weight": 1000
              },
              {
                "filter": {
                  "wildcard": {
                    "law_firm": {
                      "value": "*测试*"
                    }
                  }
                },
                "weight": 100
              },
              {
                "filter": {
                  "terms": {
                    "good_at_topic": []
                  }
                },
                "weight": 10
              }
            ],
            "min_score": 10,
            "score_mode": "sum"
          }
        }
      ]
    }
  },
  "size": 10,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    },
    {
      "like_count": {
        "order": "desc"
      }
    },
    {
      "create_time": {
        "order": "desc"
      }
    },
    {
      "id": {
        "order": "desc"
      }
    }
  ],
  "track_total_hits": true
}

   查询结果部分内容为:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 7,
    "successful": 7,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 136,
    "max_score": null,
    "hits": [
     {
        "_index": "note",
        "_id": "1952978126582046720",
        "_score": 10100,
        "_source": {
          "id": "1952978126582046720",
          "law_firm": "测试授权企业",
          "nick_name": "王五",
          "title": "测试笔记",
          "like_count": 3,
          "create_time": "2025-08-06 14:20:45"
        },
        "sort": [
          10100,
          2,
          1754490045000,
          "1952978126582046720"
        ]
      },
      {
        "_index": "note",
        "_id": "1896834568167723008",
        "_score": 10100,
        "_source": {
          "id": "1896834568167723008",
          "law_firm": "测试签约12",
          "nick_name": "李六",
          "title": "805笔记测试",
          "like_count": 2,
          "create_time": "2025-03-04 16:06:17"
        },
        "sort": [
          10000,
          8,
          1741104377000,
          "1896834568167723008"
        ]
      },
      {
        "_index": "note",
        "_id": "1912125735872598016",
        "_score": 10000,
        "_source": {
          "id": "1912125735872598016",
          "law_firm": "袁向何律师事务所",
          "nick_name": "欢乐豆0905",
          "title": "测试一下",
          "like_count": 5,
          "create_time": "2025-04-15 20:47:56"
        },
        "sort": [
          10000,
          5,
          1744750076000,
          "1912125735872598016"
        ]
      }
    ]
  }
}

 

posted @ 2025-09-16 16:02  欢乐豆123  阅读(58)  评论(0)    收藏  举报