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 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!