Elasticsearch 7.2 在 Laravel 中实践 --经纬度及距离查询
上一篇文档中选择的扩展<babenkoivan/scout-elasticsearch-driver>,该扩展已有方法whereGeoDistance查询指定经纬度范围内的数据,但是无法根据距离排序,由于依赖于laravel-scout,而该扩展并没有实现Geo的sort,但是经过通过Elasticsearch官方文档及该扩展源码的阅读,还是找到两个途径实现该功能:
1.1在ScoutBuilderServiceProvider的boot中macro排序的sort方法:
public function boot()
{
\Laravel\Scout\Builder::macro('sortRaw', function (array $value) {
$this->orders[] = $value;
return $this;
});
}
1.2在ElasticEngine的map方法中增加对sort的处理
if (isset($hit['highlight'])) {
$model->highlight = new Highlight($hit['highlight']);
}
if (isset($hit['sort'])) {
$model->sort = $hit['sort'];
}
1.3调用
$para = $request->input('para');
$position = [130, -20];
$sort_geo_distance = [
'_geo_distance' => [
'location' => $position,
'order' => 'asc',
'unit' => 'km',
'distance_type' => 'plane',
]
];
$re = Shop::search($para)
->whereGeoDistance('location', $position, '10km')
->sortRaw($sort_geo_distance) ->get();
1.4 由于该方法涉及到扩展源码的修改,所有并不推荐使用,下面是第二种比较通用的实现
2.使用已有的searchRaw方法实现排序
$position = [130, -20];
$sort_geo_distance = [
'_geo_distance' => [
'location' => $position,
'order' => 'asc',
'unit' => 'km',
'distance_type' => 'plane',
]
];
$query = [
"bool" => [
'must' => [
'match' => [
'name' => $para
]
],
"filter" => [
"geo_distance" => [
"distance" => "10000km",
"location" => $position
]
]
]
];
$result = Shop::searchRaw([
'query' => $query,
'sort' => $sort_geo_distance
]);
由于返回结果嵌套太多其他数据,并不直观,所以封装一个方法来对结果进行处理
function format_elastic_result($results)
{
return Collection::make($results['hits']['hits'])
->map(function ($hit) {
$model = $hit['_source'];
if (isset($hit['highlight'])) {
$model['highlight'] = new Highlight($hit['highlight']);
}
if (isset($hit['sort'])) {
$model['sort'] = $hit['sort'];
}
return $model;
})
->filter()
->values();
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 5年前 自动加精