电商搜索实战二 ES高级搜索

本文介绍如何在Elasticsearch中使用距离字段进行查询和排序,利用高斯函数和function_score API调整搜索结果的权重,实现更精确的地理定位搜索。同时,探讨了自定义函数对排序效果的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

带上距离字段查询

“script_fields” 意思是说通过脚本可以得到一个定制化的字段 “lang”: “expression” 为固定写法,表示这是一个表达式。


GET shop/_search
{
  "query": {
    "match": {
      "name": "凯悦"
    }
  },
  "_source": "*", 
  "script_fields": {
    "distance": {
      "script": {
        "source": "haversin(lat,lon,doc['location'].lat,doc['location'].lon)",
        "lang": "expression",
        "params": {"lat":31.37,"lon":127.12}
      }
    }
  }
}

使用距离排序

这里用到了一个排序操作,_geo_distance 为es提供的一个函数就是专门计算距离的。

GET shop/_search
{
  "query": {
    "match": {
      "name": "凯悦"
    }
  },
  "_source": "*", 
  "script_fields": {
    "distance": {
      "script": {
        "source": "haversin(lat,lon,doc['location'].lat,doc['location'].lon)",
        "lang": "expression",
        "params": {"lat":31.37,"lon":127.12}
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 31.37,
          "lon": 127.12
        },
        "order": "asc",
        "unit": "km",
        "distance_type": "arc"
        
      }
    }
  ]
}

这样操作会有一问题,排序就完全依赖于距离,不会有es中的分数计算了。
在这里插入图片描述
下面我们使用另一种方式来使用距离排序,并同时能够使用到es中的分数计算。

高斯函数计算得分

首先看看下面的json查询模型


# 使用function score 解决排序模型

GET /shop/_search
{
  "_source": "*",
  "script_fields": {
    "distance": {
      "script": {
        "source": "haversin(lat,lon,doc['location'].lat,doc['location'].lon)",
         "lang": "expression",
        "params": {"lat":31.23916171,"lon":127.48789949}
      }
    }
  },
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "name": {"query": "凯悦"}
            }},
            {"term": {
              "seller_disabled_flag": {
                "value": "0"
              }
            }}
          ]
        }
      },
      "functions": [
        {
          "gauss": {
            "location": {
              "origin": "31.23916171,127.48789949",
              "scale": "100km",
              "offset": "0km",
              "decay": 0.5
            }
          }
        }
      ]
    }
  }
}

这里我们只注意最后面的高斯函数
"location": { 表示这个高斯函数计算的是location这个字段。
"origin": "31.23916171,127.48789949", 是表示的两个参数,
其他的参数我们需要看下面的这个图来解释。

在这里插入图片描述
此图总共分为三部分, “gauss函数”,exp 批数, lin线性, 表示这三部分的区别

reference 表示origin的入参和location 我们要查询的字段之间的距离如果是0的话就会得1分。并不是只有距离等于0的时候才会得到1分, 我们可以看到上面的那条横直线都是1,直到到达offset点开始衰减,这个offset点, 我们上面的函数设置是的0,表示只要距离大于0就开始衰减。如果设置为10,那么表示方圆10km以内的门店的距离打分离都是1. 当然这只是高斯函数的得分,最终还是要结合ES的本身df/idf来计算得分。
可以从图中看到scale点以后,衰减速度就开始加快了。一但超过这个点的得分就会是decay的值,我们的案例是使用的0.5分。 当然了也不会一直是0.5,他会一直衰减,直到为0.

自定义函数影响排序效果


# 使用function score 解决排序模型

GET /shop/_search
{
  "_source": "*",
  "script_fields": {
    "distance": {
      "script": {
        "source": "haversin(lat,lon,doc['location'].lat,doc['location'].lon)",
         "lang": "expression",
        "params": {"lat":30.649819,"lon":121.651921}
      }
    }
  },
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "name": {"query": "凯悦","boost": 0.1}
            }},
            {"term": {
              "seller_disabled_flag": {
                "value": "0"
              }
            }}
          ]
        }
      },
      "functions": [
        {
          "gauss": {
            "location": {
              "origin": "30.649819,121.651921",
              "scale": "50km",
              "offset": "0km",
              "decay": 0.5
            }
          },
          "weight": 9
        },
        {
          "field_value_factor": {
            "field": "remark_score"
          },
          "weight": 0.2
        },
        {
          "field_value_factor": {
            "field": "seller_remark_score"
          },
          "weight": 0.1
        }
      ],
      "score_mode": "sum",
      "boost_mode": "sum"
    }
  }
  , "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ]
}


# 设置remark_score得分的权重, 如果remark_score本身的值为2.0 则乘以0.2 这个字段的得分就会为0.4分 这是tf/idf 打分和function打分的一种整合。
# {
#          "field_value_factor": {
#            "field": "remark_score"
#          },
#          "weight": 0.2
#        }



#  "score_mode": "sum",  代表function 函数中所有的得分的最终计算方式,默认是相乘,这里改成相加

# "boost_mode": "sum"    代表funtion 和query 之间的得分最终计算方式,默认是相乘, 这里改成相加   .
# "boost_mode": "replace" 可以使用funtion函数的得分替换到query查询的文本相关性得分。

可以看到上面的json串中,就是在自定义的函数中我使用了高斯算法,查询距离近的店面。同时又兼顾了搜索关键字的得分。 并介绍了函数与搜索关键字之间得分的设置关系。

聚合索引

"aggs": {
    "group_by_tags": {
      "terms": {
        "field": "tags",
        "size": 10
      }
    }
  }

这段代码就是一个聚合索引, aggs是固定写法。group_by_tags是可以随意定义的,用于在返回结果中显示字段名, terms是匹配形式, field 是分组的字段。size 表示按照查询出来的tags标签分组,返回前10个。 如果是1就只返回一个。

交个朋友吧。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值