带上距离字段查询
“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就只返回一个。