Elasticsearch Geopoint field type 데이터 삽입하고 정렬하기

김민규·2023년 2월 23일
0

elasticsearch

목록 보기
1/7

Elasticsearch 7.17 기반으로 작성했습니다.

📍 Geopoint field type

geo_point 필드 타입은 위도와 경도를 쌍으로 가진다.
위치 기반 쿼리를 이용해 반경 내 쿼리, 위치 기반 집계, 위치별 정렬 등을 사용할 수 있다.

이 중에서도 오늘은 정렬 기능을 활용해본다.

🔧 Mappings, Settings

간단한 스키마를 작성한다.

PUT http://localhost:9200/restaurant-index
{
    "mappings": {
        "dynamic": "strict",
        "properties": {
            "id": {
                "type": "long"
            },
            "name": {
                "type": "keyword"
            },
            "location": {
                "type": "geo_point"
            },
            "rate": {
                "type": "double"
            }
        }
    },
    "settings": {
        "index": {
            "number_of_shards": "1",
            "number_of_replicas": "0"
        }
    }
}

데이터 색인

총 6개의 음식점 데이터를 색인한다.
구글맵에서 경도와 위도를 직접 찾아서 기입했다.

임의로 찾은 가게들이다. (방문한 적 없음 🙅)

POST http://localhost:9200/_bulk
{"index":{"_index":"restaurant-index","_id":1}}
{"name":"맥도날드서울시청점","location":{"lat":37.566465,"lon":126.978116},"rate":3.9}

{"index":{"_index":"restaurant-index","_id":2}}
{"name":"남포면옥","location":{"lat":37.5672,"lon":126.9819},"rate":3.7}

{"index":{"_index":"restaurant-index","_id":3}}
{"name":"청진옥","location":{"lat":37.5719,"lon":126.9795},"rate":3.9}

{"index":{"_index":"restaurant-index","_id":4}}
{"name":"명동칼국수","location":{"lat":37.5688,"lon":126.9763},"rate":4.1}

{"index":{"_index":"restaurant-index","_id":5}}
{"name":"암소서울","location":{"lat":37.5699,"lon":126.9729},"rate":4.6}

{"index":{"_index":"restaurant-index","_id":6}}
{"name":"무교동북어국집","location":{"lat":37.5679,"lon":126.9799},"rate":4.5}

정렬하기

GET http://localhost:9200/restaurant-index/_search
{
    "query": {
        "bool": {
            "must": {
                "match_all": {}
            }
        }
    },
    "from": 0,
    "size": 10,
    "sort": [
        {
            "_geo_distance": {
                "location": {
                    "lat": 37.5692,
                    "lon": 126.9787
                },
                "order": "asc",
                "unit": "m",
                "mode": "min"
            }
        }
    ],
    "aggs": {}
}

쿼리 결과는 아래와 같다.

{
    ...
    "hits": {
        "total": {
            "value": 6,
            ...
        },
        "hits": [
            {
                ...
                "_id": "6",
                "_score": null,
                "_source": {
                    "name": "무교동북어국집",
                    ...
                },
                "sort": [
                    179.11076153612436
                ]
            },
            {
                ...
                "_id": "4",
                "_score": null,
                "_source": {
                    "name": "명동칼국수",
                    ...
                },
                "sort": [
                    253.22551326764062
                ]
            },
            ...
        ]
    }
}

geo_distance.location으로 넣은 위치는 청계천이다. (아래 사진 참조)
청계천으로부터 직선거리로 음식점들의 거리를 계산하고 가까운 순(asc)으로 정렬한다.

검색 결과는 무교동북어국집 > 명동칼국수 > 맥도날드서울시청점 > 청진옥 > 남포면옥 > 암소서울 순서로 정렬된다.
검색 결과 항목 중에 sort 는 실제 직선거리를 나타낸다.(여기서는 meter 단위)

Painless Script 이용하여 정렬하기

GET http://localhost:9200/restaurant-index/_search
{
    "query": {
        "bool": {
            "must": {
                "match_all": {}
            }
        }
    },
    "from": 0,
    "size": 10,
    "sort": [
        {
            "_script": {
                "type": "number",
                "script": {
                    "lang": "painless",
                    "source": "doc['location'].arcDistance(params.lat, params.lon)",
                    "params": {
                        "lat": 37.5692,
                        "lon": 126.9787
                    }
                },
                "order": "asc"
            }
        }
    ],
    "aggs": {}
}

arcDistance 를 활용한 스크립트 정렬방식이다.
앞서 살펴봤던 _geo_distance 를 이용한 정렬 방식과 동일한 결과를 볼 수 있다.

하지만 스크립트를 사용하면 다른 데이터와 부가적인 계산을 하거나 유연한 계산식을 구현할 수 있을거 같다.

위에서 사용한 스크립트는 https://github.com/goldcrestwilma/elasticsearch/tree/main/restaurant-index에서 확인할 수 있다.


참조

profile
Backend Engineer, Vim User

0개의 댓글