EFK 配置geo-ip落地实践(三)经纬度数据查询及格式化输出

栏目: 后端 · 发布时间: 6年前

内容简介:经过之前的工作,目前已经完成了数据地图的数据格式化和录入记录,目前我们的数据地图项目已经进行到最后阶段,所以现在需要一个接口,进行格式化数据并输出,其中需要用到Elasticsearch的全文检索,检索出数据后,使用php接口格式化数据输出例如,一个小时内,在中国范围内,各个经纬度坐标的,有操作行为的,用户个数由此需求,可以得到相应的Elasticsearch的搜索语句,如下:

经过之前的工作,目前已经完成了数据地图的数据格式化和录入记录,目前我们的数据地图项目已经进行到最后阶段,所以现在需要一个接口,进行格式化数据并输出,其中需要用到Elasticsearch的全文检索,检索出数据后,使用 php 接口格式化数据输出

一、全文检索

  1. 搜索条件(时间,空间)
  2. 输出结果(用户数量)

例如,一个小时内,在中国范围内,各个经纬度坐标的,有操作行为的,用户个数

由此需求,可以得到相应的Elasticsearch的搜索语句,如下:

{
"size": 0,
"aggs": {
    "filter_agg": {
        "filter": {
            "geo_bounding_box": {
                "location": {
                    "top_left": {
                        "lat": 90,
                        "lon": -34.453125
                    },
                    "bottom_right": {
                        "lat": -90,
                        "lon": 34.453125
                    }
                }
            }
        },
        "aggs": {
            "2": {
                "geohash_grid": {
                    "field": "location",
                    "precision": 2
                },
                "aggs": {
                    "3": {
                        "geo_centroid": {
                            "field": "location"
                        }
                    }
                }
            }
        }
    }
},
"stored_fields": [
    "*"
],
"docvalue_fields": [
    "@timestamp"
],
"query": {
    "bool": {
        "must": [
            {
                "range": {
                    "@timestamp": {
                        "gte": 1542692193461,
                        "lte": 1542695793461,
                        "format": "epoch_millis"
                    }
                }
            }
        ]
    }
}
}
复制代码
  1. size=0表示不分页
  2. query为搜索主体,其中的必要条件为时间参数,即,搜索此段时间内的所有数据
  3. aggs中相当于spl中的where条件,而其中geo_bounding_box为地理范围,由左上角经纬度点到右下角经纬度点所界定的一个矩形方框。
  4. aggs嵌套,即上层条件的结果上,继续做筛选
  5. geohash_grid表示,按照你定义的精度计算每一个点的 geohash 值而将附近的位置聚合在一起,其中field为目前筛选的的字段, precision为经度,单位为km
  6. 最后,通过geo_centroid得到key为location的聚合数据

结果数据格式如下:

{
"took": 428,
"timed_out": false,
"_shards": {
    "total": 131,
    "successful": 126,
    "skipped": 121,
    "failed": 5,
    "failures": [
        {
            "shard": 0,
            "index": "elastalert_status_status",
            "node": "w10b9zEBRpuUEQsWvNqEig",
            "reason": {
                "type": "query_shard_exception",
                "reason": "failed to find geo_point field [location]",
                "index_uuid": "Dm4dpUtTTHitYN-TZFC-1g",
                "index": "elastalert_status_status"
            }
        }
    ]
},
"hits": {
    "total": 360942,
    "max_score": 0,
    "hits": []
},
"aggregations": {
    "filter_agg": {
        "2": {
            "buckets": [
                {
                    "3": {
                        "location": {
                            "lat": 48.58949514372008,
                            "lon": 7.584022147181843
                        },
                        "count": 252
                    },
                    "key": "u0",
                    "doc_count": 252
                },
                {
                    "3": {
                        "location": {
                            "lat": 54.420127907268785,
                            "lon": -3.120888938036495
                        },
                        "count": 181
                    },
                    "key": "gc",
                    "doc_count": 181
                },
                {
                    "3": {
                        "location": {
                            "lat": 42.32862451614172,
                            "lon": 3.7518564593602917
                        },
                        "count": 67
                    },
                    "key": "sp",
                    "doc_count": 67
                },
                {
                    "3": {
                        "location": {
                            "lat": 45.40799999143928,
                            "lon": 11.88589995726943
                        },
                        "count": 21
                    },
                    "key": "u2",
                    "doc_count": 21
                },
                {
                    "3": {
                        "location": {
                            "lat": 46.65579996071756,
                            "lon": 32.61779992841184
                        },
                        "count": 1
                    },
                    "key": "u8",
                    "doc_count": 1
                }
            ]
        },
        "doc_count": 522
    }
}
}
复制代码
  1. aggregations中是我们最终需要的数据
  2. 其中location为聚合的经纬度坐标,紧跟着的count则指的是,在此点2km*2km范围之内的用户数。

自此,我们首先明白了,在Elasticsearch,如何书写search语句查询我们想要的东西。 接下来,我们需要书写相应的php接口,来格式化输出数据

二、接口书写

  1. 使用Elasticseach的PHP API
  2. 确定输入参数:时间范围,空间范围
  3. 确定输出数据结构,并格式化数据输出

代码如下,有注释:

<?php
/**
 * Created by PhpStorm.
 * User: ekisong
 * Date: 2018/11/13
 * Time: 15:55
 */
require 'vendor/autoload.php';
ini_set('display_errors','on');
error_reporting(E_ALL);

use Elasticsearch\ClientBuilder;

//创建Elasticsearch 的搜索对象client
$client = ClientBuilder::create()->setHosts(["localhost:9200"])->build();

//需要被筛选的字段名,默认值为location
$fieldName = isset($_GET['field']) ? $_GET['field'] : 'location';

//地理围栏左上角纬度,默认值90
$topLeftLat = isset($_GET['top_left_lat']) ? $_GET['top_left_lat'] : 90;

//地理围栏左上角经度,默认值-180
$topLeftLon = isset($_GET['top_left_lon']) ? $_GET['top_left_lon'] : -180;

//地理围栏右下角纬度,默认值-90
$bottomRightLat = isset($_GET['bottom_right_lat']) ? $_GET['bottom_right_lat'] : -90;

//地理围栏右下角经度,默认值180
$bottomRightLon = isset($_GET['bottom_right_lon']) ? $_GET['bottom_right_lon'] : 180;

//时间范围结束时间,默认当前时间
$endTime = isset($_GET['end_time']) ? $_GET['end_time'] : time()*1000;

//时间范围其实时间,默认当前时间前15分钟
$startTime = isset($_GET['start_time']) ? $_GET['start_time'] : $endTime - 15*60*1000;

//创建查询结构体
$body = [
    'size' => 0,
    'query' => [
        'bool' => [
            'must' => [
                [
                    'range' => [
                        '@timestamp' => [
                            'gte' => $startTime,
                            'lte' => $endTime,
                            'format' => 'epoch_millis'
                        ]
                    ]
                ]
            ]
        ]
    ],
    'aggs' => [
        'filter_agg' => [
            'filter' => [
                'geo_bounding_box' => [
                    'location' => [
                        'top_left' => [
                            'lat' => $topLeftLat,
                            'lon' => $topLeftLon
                        ],
                        'bottom_right' => [
                            'lat' => $bottomRightLat,
                            'lon' => $bottomRightLon
                        ]
                    ]
                ]
            ],
            'aggs' => [
                '2' => [
                    'geohash_grid' => [
                        'field' => $fieldName,
                        'precision' => 1
                    ],
                    'aggs' => [
                        '3' => [
                            'geo_centroid' => [
                                'field' => $fieldName
                            ]
                        ]
                    ]
                ]
            ]
        ]
    ],
    'stored_fields' => [
        '*'
    ],
    'docvalue_fields' => [
        '@timestamp'
    ]
];

//搜索参数
$params = [
    'index' => 'logstash-*',
    'body' => $body
];

//Elasticsearch搜索结果原始数据
$response = $client->search($params);

$resultTmp = $response['aggregations']['filter_agg']['2']['buckets'];

$data = array();

//格式化数据
foreach ($resultTmp as $doc)
{
    $lat = $doc['3'][$fieldName]['lat'];
    $lon = $doc['3'][$fieldName]['lon'];
    $count = $doc['doc_count'];
    $tmp = [
        'count' => $count,
        'geometry' => [
            'type' => 'Point',
            'coordinates' => [$lon,$lat]
        ]
    ];
    $data[] = $tmp;
}

$result = array('data'=>$data,'error_msg'=>'','flag'=>1);

if (empty($data))
{
    $result['error_msg'] = 'no data';
    $result['flag'] = 0;
}

//最终输出
echo json_encode($result);
exit();
复制代码

由于H5页面插件限制,所以需要特定的数据格式。所以最终输出结果如下:

[{
    "count": 6,
    "geometry": {
        "type": "Point",
        "coordinates": ["116.395645", "39.929986"]
    }
}, {
    "count": 6,
    "geometry": {
        "type": "Point",
        "coordinates": ["121.487899", "31.249162"]
    }
}, {
    "count": 5,
    "geometry": {
        "type": "Point",
        "coordinates": ["117.210813", "39.14393"]
    }
}, {
    "count": 4,
    "geometry": {
        "type": "Point",
        "coordinates": ["106.530635", "29.544606"]
    }
}]
复制代码

至此,我们数据地图项目在数据方面的工作暂且告一段落。

参考文档:

www.elastic.co/guide/en/el…

www.elastic.co/guide/en/elasticsearch/reference/current/search.html

www.elastic.co/guide/cn/el…


以上所述就是小编给大家介绍的《EFK 配置geo-ip落地实践(三)经纬度数据查询及格式化输出》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

软件测试的艺术

软件测试的艺术

梅尔斯 / 机械工业出版社 / 2006年01月 / 22.0

《软件测试的艺术》(原书第2版)成功、有效地进行软件测试的实用策略和技术:    基本的测试原理和策略      验收测试    程序检查和走查         安装测试    代码检查            模块(单元)测试    错误列表            测试规划与控制    同行评分            独立测试机构    黑盒、白盒测试    ......一起来看看 《软件测试的艺术》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具