<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Craig Taverner - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Craig Taverner - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/kr/search-labs/author/craig-taverner</link>
    </image>
    <link>https://www.elastic.co/kr/search-labs/author/craig-taverner</link>
    <atom:link href="https://www.elastic.co/kr/search-labs/rss/author/craig-taverner.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[kr]]></language>
    <lastBuildDate>Wed, 23 Sep 2026 04:33:13 GMT</lastBuildDate>
  <item>
    <title><![CDATA[ES|QL에서 사용하기 위해 Kibana를 사용하여 위치 기반 정보 데이터를 Elasticsearch로 수집하기]]></title>
    <description><![CDATA[Kibana와 csv 수집 프로세서를 사용하여 Elasticsearch 쿼리 언어(ES|QL)에서 검색에 사용할 수 있도록 위치 기반 정보 데이터를 Elasticsearch로 수집하는 방법을 알아보세요. Elasticsearch는 강력한 위치 기반 정보 검색 기능을 갖추고 있으며, 이제 사용 편의성과 OGC 친숙도를 획기적으로 개선하기 위해 ES|QL에 제공됩니다. 하지만 이러한 기능을 사용하려면 지리공간 데이터가 필요합니다.]]></description>
    <content:encoded><![CDATA[<p>최근에 Elasticsearch의 새롭고 강력한 <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">파이핑 쿼리 언어인</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">ES|QL에서 새로운</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">위치 기반</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">정보</a> 검색 기능을 사용하는 방법을 설명하는 블로그가 게시되었습니다. 이러한 기능을 사용하려면 Elasticsearch에 위치 기반 정보 데이터가 있어야 합니다. 따라서 이 블로그에서는 지리공간 데이터를 수집하는 방법과 ES|QL 쿼리에서 이를 사용하는 방법을 보여드리겠습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" alt="ESQL 지리공간 검색" /><h2>Kibana를 사용하여 위치 기반 정보 데이터 가져오기</h2><p>이전 블로그의 예제에 사용된 데이터는 내부적으로 통합 테스트에 사용하는 데이터를 기반으로 했습니다. 사용자의 편의를 위해 Kibana를 사용하여 쉽게 가져올 수 있는 몇 가지 CSV 파일 형태로 여기에 포함시켰습니다. 데이터는 공항, 도시, 도시 경계가 혼합되어 있습니다. 다음에서 데이터를 다운로드할 수 있습니다:</p><ul><li><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">airports.csv</a></p><ul><li><p>여기에는 세 개의 데이터 세트가 병합되어 있습니다:</p><ul><li><p><a href="https://www.naturalearthdata.com/downloads/10m-cultural-vectors/airports/">Natural Earth의</a>공항(이름, 위치 및 관련 데이터)</p></li><li><p><a href="https://simplemaps.com/data/world-cities">SimpleMaps의</a>도시 위치</p></li><li><p><a href="https://www.partow.net/miscellaneous/airportdatabase/">전 세계 공항 데이터베이스의</a>공항 고도</p></li></ul></li></ul></li><li><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airport_city_boundaries.csv">airport_city_boundaries.csv</a></p><ul><li><p>여기에는 위의 공항 및 도시 이름이 하나의 새로운 소스로 병합되어 있습니다:</p><ul><li><p><a href="https://www.openstreetmap.org/">오픈스트리트맵의</a>도시 경계</p></li></ul></li></ul></li></ul><p>짐작할 수 있듯이, ES|QL의 지리적 공간 기능을 테스트하기 위해 이러한 데이터 소스를 위의 두 파일로 결합하는 데 시간을 보냈습니다. 구체적인 데이터 요구 사항과 완전히 같지는 않을 수 있지만, 이를 통해 어떤 것이 가능한지에 대한 아이디어를 얻을 수 있기를 바랍니다. 특히 몇 가지 흥미로운 점을 보여드리고자 합니다:</p><ul><li><p>다른 색인 가능한 데이터와 함께 지리공간 필드가 있는 데이터 가져오기</p></li><li><p><code>geo_point</code> 및 <code>geo_shape</code> 데이터를 모두 가져와 쿼리에서 함께 사용</p></li><li><p>공간 관계를 사용하여 조인할 수 있는 두 인덱스로 데이터 가져오기</p></li><li><p>향후 가져오기를 용이하게 하기 위한 수집 파이프라인 생성(Kibana 이후)</p></li><li><p>수집 프로세서의 몇 가지 예는 <code>csv</code>, <code>convert</code> 및 <code>split</code></p></li></ul><p>이 블로그에서는 CSV 데이터 작업에 대해 설명하지만,<a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">Kibana를</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">사용해 위치 기반 데이터를 추가하는</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">방법에는</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">여러 가지가 있다는 것을</a> 이해하는 것이 중요합니다. 맵 애플리케이션 내에서 CSV, GeoJSON 및 ESRI 셰이프파일과 같은 구분된 데이터를 업로드할 수 있으며 맵에서 직접 도형을 그릴 수도 있습니다. 이 블로그에서는 Kibana 홈 페이지에서 CSV 파일을 가져오는 데 중점을 두겠습니다.</p><h3>공항 가져오기</h3><p>첫 번째 파일인 <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">airports.csv</a>, 에는 우리가 처리해야 할 몇 가지 흥미로운 문제가 있습니다. 첫째, 열에는 CSV 파일에서는 일반적으로 볼 수 없는 추가 공백이 열을 구분합니다. 둘째, <code>type</code> 필드는 다중 값 필드이므로 별도의 필드로 분할해야 합니다. 마지막으로 일부 필드는 문자열이 아니므로 올바른 유형으로 변환해야 합니다. 이 모든 작업은 Kibana의 CSV 가져오기 기능을 사용하여 수행할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt393bc416bf425301/6a16f707839dfa1e86dcfca9/b1afd8c95973bec32f229a9adfaef14680b09a8e-1944x478.png" alt="Kibana 업로드 - 미리보기" /><p>Kibana 홈페이지에서 시작하세요. "통합을 추가하여 시작하기" 라는 섹션이 있으며, 여기에는 "파일 업로드" 라는 링크가 있습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte12fc741edab20d3/6a16f709acf088600fbe98bf/996372bb3a52859cc840bd1d8f984a33a0e7ada3-1180x410.png" alt="Kibana 홈 - 파일 업로드" /><p>이 링크를 클릭하면 "파일 업로드" 페이지로 이동합니다. 여기에서 <code>airports.csv</code> 파일을 끌어다 놓으면 Kibana가 파일을 분석하여 데이터 미리 보기를 표시합니다. 구분 기호를 쉼표로, 첫 번째 행을 헤더 행으로 자동으로 감지해야 합니다. 그러나 모든 필드가 <code>text</code> 또는 <code>keyword</code> 이라고 가정하여 열 사이의 여분의 공백을 잘라내거나 필드 유형을 결정하지 않았을 수 있습니다. 이 문제를 해결해야 합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf65a09ec0c7a61ad/6a16f70ad7c0227aedde626f/1d9ffa6cdbc0d67a228be1a747ec1ebda6a63099-1800x538.png" alt="Kibana 업로드 - 미리보기" /><p><code>Override settings</code> 을 클릭하고 <code>Should trim fields</code>, <code>Apply</code> 확인란을 선택하여 설정을 닫습니다. 이제 필드 유형을 수정해야 합니다. 다음 페이지에서 <code>Import</code> 을 클릭하세요.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda9a5f85d8e693dc/6a16f70c60084b72f53c4348/a97aceffb1858eae26a213336913505ae9923b03-1800x526.png" alt="Kibana 업로드 - 가져오기" /><p>먼저 인덱스 이름을 선택한 다음 <code>Advanced</code> 을 선택하여 필드 매핑 및 수집 프로세서 페이지로 이동합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56705083cdd9eb18/6a16f70d66c4f93350f8bdbb/058b0fb09da0b8d7f9c9b0a9c83b8b485ce43925-1440x629.png" alt="Kibana 업로드 - 필드 매핑" /><p>여기서는 인덱스에 대한 필드 매핑과 데이터를 가져오기 위한 수집 파이프라인을 모두 변경해야 합니다. 첫째, Kibana는 <code>scalerank</code> 필드를 <code>long</code> 으로 자동 감지했지만 <code>location</code> 및 <code>city_location</code> 필드를 <code>keyword</code> 로 잘못 인식했을 가능성이 높습니다. <code>geo_point</code> 으로 편집하면 다음과 같은 매핑이 완성됩니다:</p>{
  "properties": {
    "abbrev":        { "type": "keyword" },
    "city":          { "type": "keyword" },
    "city_location": { "type": "geo_point" },
    "country":       { "type": "keyword" },
    "elevation":     { "type": "double" },
    "location":      { "type": "geo_point" },
    "name":          { "type": "text" },
    "scalerank":     { "type": "long" },
    "type":          { "type": "keyword" }
  }
}<p>여기에는 약간의 유연성이 있지만, 어떤 유형을 선택하느냐에 따라 필드가 색인되는 방식과 가능한 쿼리 종류에 영향을 미칩니다. 예를 들어 <code>location</code> 을 <code>keyword</code> 으로 남겨두면 지리공간 검색 쿼리를 수행할 수 없습니다. 마찬가지로 <code>elevation</code> 을 <code>text</code> 으로 남겨두면 숫자 범위 쿼리를 수행할 수 없습니다.</p><p>이제 수집 파이프라인을 수정할 차례입니다. Kibana가 <code>scalerank</code> 를 위의 <code>long</code> 로 자동 감지했다면, 필드를 <code>long</code> 로 변환하는 프로세서도 추가했을 것입니다. <code>elevation</code> 필드에 비슷한 프로세서를 추가해야 하는데, 이번에는 <code>double</code> 으로 변환합니다. 파이프라인을 편집하여 이 변환이 제대로 이루어지도록 합니다. 이를 저장하기 전에 <code>type</code> 필드를 여러 필드로 분할하는 변환을 한 번 더 수행하려고 합니다. 다음 구성을 사용하여 파이프라인에 <code>split</code> 프로세서를 추가합니다:</p>{
  "split": {
    "field": "type",
    "separator": ":",
    "ignore_missing": true
  }
}<p>최종 수집 파이프라인은 다음과 같아야 합니다:</p>{
  "description": "Ingest pipeline created by text structure finder",
  "processors": [
    {
      "csv": {
        "field": "message",
        "target_fields": [
          "abbrev",
          "name",
          "scalerank",
          "type",
          "location",
          "country",
          "city",
          "city_location",
          "elevation"
        ],
        "ignore_missing": false,
        "trim": true
      }
    },
    {
      "convert": {
        "field": "scalerank",
        "type": "long",
        "ignore_missing": true
      }
    },
    {
      "convert": {
        "field": "elevation",
        "type": "double",
        "ignore_missing": true
      }
    },
    {
      "split": {
        "field": "type",
        "separator": ":",
        "ignore_missing": true
      }
    },
    {
      "remove": {
        "field": "message"
      }
    }
  ]
}<p><code>location</code> 및 <code>city_location</code> 필드에 변환 프로세서를 추가하지 않았습니다. 이는 필드 매핑의 <code>geo_point</code> 유형이 이미 이러한 필드에 있는 데이터의 WKT 형식을 이해하고 있기 때문입니다. <code>geo_point</code> 유형은 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html">WKT, GeoJSON 등을</a> 포함한 다양한 형식을 이해할 수 있습니다. 예를 들어 CSV 파일에 <code>latitude</code> 와 <code>longitude</code> 에 대한 두 개의 열이 있는 경우, 이를 단일 <code>geo_point</code> 필드로 결합하려면 <code>script</code> 또는 <code>set</code> 프로세서를 추가해야 합니다(예. <code>"set": {"field": "location", "value": "{{lat}},{{lon}}"}</code>).</p><p>이제 파일을 가져올 준비가 되었습니다. <code>Import</code> 을 클릭하면 방금 정의한 매핑과 수집 파이프라인을 사용하여 데이터를 인덱스로 가져옵니다. 데이터를 수집하는 데 오류가 있는 경우, Kibana가 여기에 보고하므로 소스 데이터 또는 수집 파이프라인을 편집하고 다시 시도할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte81621425c7289c5/6a16f70f839dfaf608dcfcad/55dde2940c7aba66ce8257d15007ef797b8a5107-1440x415.png" alt="Kibana 업로드 - 가져오기" /><p>새 수집 파이프라인이 생성된 것을 확인할 수 있습니다. 이는 Kibana의 <code>Stack Management</code> 섹션으로 이동하여 <code>Ingest pipelines</code> 을 선택하면 볼 수 있습니다. 여기에서 방금 만든 파이프라인을 확인하고 필요한 경우 편집할 수 있습니다. 실제로 <code>Ingest pipelines</code> 섹션은 수집 파이프라인을 만들고 테스트하는 데 사용할 수 있으며, 훨씬 더 복잡한 수집을 계획하는 경우 매우 유용한 기능입니다.</p><p>이 데이터를 바로 살펴보고 싶다면 뒷부분으로 건너뛰고, 도시 경계도 가져오려면 계속 읽으세요.</p><h3>도시 경계 가져오기</h3><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airport_city_boundaries.csv">airport_city_boundaries.csv에서</a> 제공되는 도시 경계 파일은 이전 예제보다 가져오기가 조금 더 간단합니다. 여기에는 도시 경계를 <code>POLYGON</code> 으로 표현하는 WKT 필드인 <code>city_boundary</code> 필드와 도시 위치를 <code>geo_point</code> 으로 표현하는 <code>city_location</code> 필드가 포함되어 있습니다. 이 데이터는 공항 데이터와 비슷한 방식으로 가져올 수 있지만 몇 가지 차이점이 있습니다:</p><ul><li><p>자동 감지되지 않았기 때문에 재정의 설정 <code>Has header row</code> 을 선택해야 했습니다.</p></li><li><p>데이터에 여분의 공백이 이미 정리되어 있었기 때문에 필드를 다듬을 필요가 없었습니다.</p></li><li><p>모든 유형이 문자열 또는 공간 유형이었기 때문에 수집 파이프라인을 편집할 필요가 없었습니다.</p></li><li><p>하지만 필드 매핑을 편집하여 <code>city_boundary</code> 필드를 <code>geo_shape</code>, <code>city_location</code> 필드를 다음과 같이 설정해야 했습니다. <code>geo_point</code></p></li></ul><p>최종 필드 매핑은 다음과 같습니다:</p>{
  "properties": {
    "abbrev":        { "type": "keyword" },
    "airport":       { "type": "keyword" },
    "city":          { "type": "keyword" },
    "city_boundary": { "type": "geo_shape" },
    "city_location": { "type": "geo_point" },
    "region":        { "type": "text" }
  }
}<p>앞서 <code>airports.csv</code> 가져오기와 마찬가지로 <code>Import</code> 을 클릭하여 데이터를 인덱스로 가져오기만 하면 됩니다. 데이터는 우리가 편집한 매핑과 Kibana가 정의한 수집 파이프라인으로 가져옵니다.</p><h3>개발 도구로 지리공간 데이터 탐색하기</h3><p>Kibana에서는 일반적으로 "검색" 을 사용하여 색인된 데이터를 탐색합니다. 그러나 ES|QL 쿼리를 사용하여 직접 앱을 작성하려는 경우, 원시 Elasticsearch API에 액세스하는 것이 더 흥미로울 수 있습니다. Kibana에는 쿼리 작성을 실험해 볼 수 있는 편리한 콘솔이 있습니다. 이를 <code>Dev Tools</code> 콘솔이라고 하며, Kibana 사이드바에서 찾을 수 있습니다. 이 콘솔은 Elasticsearch 클러스터와 직접 통신하며 쿼리 실행, 인덱스 생성 등에 사용할 수 있습니다.</p><p>다음을 시도해 보세요:</p>POST /_query?error_trace=true&amp;format=txt
{
  "query": """
FROM airports
| EVAL distance = ST_DISTANCE(city_location, TO_GEOPOINT("POINT(12.565 55.673)"))
| WHERE distance &lt; 1000000 AND scalerank &lt; 6 AND distance &gt; 10000
| SORT distance ASC
| KEEP distance, abbrev, name, location, country, city, elevation
| LIMIT 10
  """
}<p>이렇게 하면 다음과 같은 결과가 표시됩니다:</p><p>거리</p><p>abbrev</p><p>이름</p><p>장소</p><p>국가</p><p>도시</p><p>고도</p><p>273418.05776847183</p><p>HAM</p><p>함부르크</p><p>포인트 (10.005647830925 53.6320011640866)</p><p>독일</p><p>노르트슈테트</p><p>17.0</p><p>337534.653466062</p><p>TXL</p><p>베를린-테겔 국제 공항</p><p>포인트 (13.2903090925074 52.5544287044101)</p><p>독일</p><p>호헨 노이엔도르프</p><p>38.0</p><p>483713.15032266214</p><p>OSL</p><p>오슬로 가르데르멘</p><p>포인트 (11.0991032762581 60.1935783171386)</p><p>노르웨이</p><p>오슬로</p><p>208.0</p><p>522538.03148094116</p><p>BMA</p><p>브롬마</p><p>포인트 (17.9456175406145 59.3555902065112)</p><p>스웨덴</p><p>스톡홀름</p><p>15.0</p><p>522538.03148094116</p><p>ARN</p><p>Arlanda</p><p>포인트 (17.9307299016916 59.6511203397372)</p><p>스웨덴</p><p>스톡홀름</p><p>38.0</p><p>624274.8274399083</p><p>DUS</p><p>뒤셀도르프 국제 공항</p><p>POINT (6.76494446612174 51.2781820420774)</p><p>독일</p><p>뒤셀도르프</p><p>45.0</p><p>633388.6966435644</p><p>PRG</p><p>루진</p><p>포인트 (14.2674849854076 50.1076511703671)</p><p>체코</p><p>프라하</p><p>381.0</p><p>635911.1873311149</p><p>AMS</p><p>스키폴</p><p>POINT (4.76437693232812 52.3089323889822)</p><p>네덜란드</p><p>Hoofddorp</p><p>-3.0</p><p>670864.137958866</p><p>FRA</p><p>프랑크푸르트 국제</p><p>포인트 (8.57182286907608 50.0506770895207)</p><p>독일</p><p>프랑크푸르트</p><p>111.0</p><p>683239.2529970079</p><p>WAW</p><p>오케시에 국제</p><p>포인트 (20.9727263383587 52.171026749259)</p><p>폴란드</p><p>Piaseczno</p><p>111.0</p><h2>Kibana Maps로 위치 기반 정보 데이터 시각화하기</h2><p>Kibana Maps는 위치 기반 정보 데이터를 시각화하기 위한 강력한 도구입니다. 여러 레이어가 있는 맵을 만드는 데 사용할 수 있으며, 각 레이어는 서로 다른 데이터 집합을 나타냅니다. 데이터는 다양한 방식으로 필터링, 집계, 스타일 지정이 가능합니다. 이 섹션에서는 이전 섹션에서 가져온 데이터를 사용하여 Kibana Maps에서 지도를 만드는 방법을 보여드리겠습니다.</p><p>Kibana 메뉴에서 <code>Analytics</code>-&gt;<code>Maps</code> 으로 이동하여 새 지도 보기를 엽니다. <code>Add Layer</code> 을 클릭하고 <code>Documents</code> 을 선택하여 데이터 보기 <code>airports</code> 를 선택한 다음 레이어 스타일을 편집하여 <code>elevation</code> 필드를 사용하여 마커에 색상을 지정하면 각 공항의 높이를 쉽게 확인할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcc4736d88c1abc9/6a16f7102b835f7353f4afca/9e63726d7c059331e6e20e474f8abee53dc2cbb4-840x388.png" alt="Kibana 지도 - 공항 레이어 스타일" /><p>'변경 사항 유지'를 클릭하여 지도를 저장합니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ec3cc535b5c21d8/6a16f71375879ec091fe15dc/32ad1dadb5d341a2b66662c58638b781122fc22c-2852x1528.png" alt="Kibana 지도 - 공항" /><p>이제 두 번째 레이어를 추가하고 이번에는 <code>airport_city_boundaries</code> 데이터 보기를 선택합니다. 이번에는 <code>city_boundary</code> 필드를 사용하여 레이어 스타일을 지정하고 채우기 색상을 하늘색으로 설정하겠습니다. 그러면 지도에 도시 경계가 표시됩니다. 공항 마커가 맨 위에 오도록 레이어를 다시 정렬해야 합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2932d7ff4a7206c9/6a16f7156f7f0409f09145c7/53dd65026f9a98c13f2cc4f9328a79242f0b70de-2854x1510.png" alt="Kibana 지도 - 도시 경계 레이어 스타일" /><h2>공간 조인</h2><p>ES|QL은 <code>JOIN</code> 명령을 지원하지 않지만 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich">명령을</a> 사용하여 특별한 경우의 조인을 수행할 수 있습니다. 이 명령은 SQL의 'Left 조인'과 유사하게 작동하며, 두 데이터 집합 간의 공간적 관계를 기반으로 한 인덱스의 결과를 다른 인덱스의 데이터로 보강할 수 있습니다.</p><p>예를 들어 공항 위치가 포함된 도시 경계를 찾아서 공항이 취항하는 도시에 대한 추가 정보로 공항 테이블의 결과를 보강한 다음 결과에 대한 몇 가지 통계를 수행해 보겠습니다:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| STATS
    centroid = ST_CENTROID_AGG(location),
    count = COUNT(city_location)
    BY region
| SORT count DESC
| LIMIT 10<p>색인 강화 인덱스를 먼저 준비하지 않고 이 쿼리를 실행하면 다음과 같은 오류 메시지가 표시됩니다:</p>cannot find enrich policy [city_boundaries]<p>앞서 언급했듯이 ES|QL은 진정한 <code>JOIN</code> 명령을 지원하지 않기 때문입니다. 그 중요한 이유 중 하나는 Elasticsearch가 분산 시스템이고 조인이 확장하기 어려울 수 있는 고비용 작업이라는 점입니다. 그러나 <code>ENRICH</code> 명령은 클러스터 전체에 복제된 특별히 준비된 강화 인덱스를 사용하여 각 노드에서 로컬 조인을 수행할 수 있기 때문에 매우 효율적일 수 있습니다.</p><p>이를 더 잘 이해하기 위해 위의 쿼리에서 <code>ENRICH</code> 명령에 초점을 맞춰 보겠습니다:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary<p>이 명령은 <code>airports</code> 인덱스에서 검색된 결과를 보강하고 원본 인덱스의 <code>city_location</code> 필드와 앞서 몇 가지 예제에서 사용한 <code>airport_city_boundaries</code> 인덱스의 <code>city_boundary</code> 필드 간에 <code>intersects</code> 조인을 수행하도록 Elasticsearch에 지시합니다. 그러나 이 정보 중 일부는 이 쿼리에서 명확하게 표시되지 않습니다. 우리가 볼 수 있는 것은 인라이크 정책의 이름 <code>city_boundaries</code> 이며, 누락된 정보는 해당 정책 정의에 캡슐화되어 있습니다.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>여기에서 <code>geo_match</code> 쿼리를 수행하고(<code>intersects</code> 이 기본값), 일치시킬 필드는 <code>city_boundary</code>, <code>enrich_fields</code> 은 원본 문서에 추가하려는 필드임을 알 수 있습니다. 이러한 필드 중 하나인 <code>region</code> 은 실제로 <code>STATS</code> 명령의 그룹화 키로 사용되었는데, 이 '왼쪽 조인' 기능이 없었다면 불가능했을 것입니다. 인라이크 정책에 대한 자세한 내용은 인라이크 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">문서를</a> 참조하세요.</p><p>Elasticsearch의 강화 인덱스와 정책은 원래 준비된 다른 강화 인덱스의 데이터를 사용하여 인덱스 시점에 데이터를 강화하도록 설계되었습니다. 그러나 ES|QL에서는 <code>ENRICH</code> 명령이 쿼리 시점에 작동하며 수집 파이프라인을 사용할 필요가 없습니다. 이렇게 하면 사실상 SQL <code>LEFT JOIN</code> 과 매우 유사하지만, 두 인덱스를 조인할 수 없고 왼쪽에는 일반 인덱스만 있고 오른쪽에는 특별히 준비된 강화 인덱스가 있다는 점이 다릅니다.</p><p>수집 파이프라인이든 ES|QL에서 사용하든 어느 경우든, 수집 인덱스와 정책을 설정하기 위해 몇 가지 준비 단계를 수행해야 합니다. 위에서 이미 <code>airport_city_boundaries</code> 인덱스를 가져왔지만 <code>ENRICH</code> 명령에서 이 인덱스를 직접 색인 강화 인덱스로 사용할 수 없습니다. 먼저 두 단계를 수행해야 합니다:</p><ul><li><p>위에서 설명한 보강 정책을 생성하여 소스 인덱스, 일치시킬 소스 인덱스의 필드, 일치하면 반환할 필드를 정의합니다.</p></li><li><p>이 정책을 실행하여 보강 인덱스를 생성합니다. 이렇게 하면 원본 소스 인덱스를 보다 효율적인 데이터 구조로 읽고 클러스터 전체에 복사하여 특별한 내부 인덱스를 구축합니다.</p></li></ul><p>인리치 정책은 다음 명령을 사용하여 만들 수 있습니다:</p>PUT /_enrich/policy/city_boundaries
{
  "match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>그리고 다음 명령을 사용하여 정책을 실행할 수 있습니다:</p>POST /_enrich/policy/city_boundaries/_execute<p><code>airport_city_boundaries</code> 인덱스의 콘텐츠를 변경하는 경우 이 정책을 다시 실행해야 변경 사항이 인리치 인덱스에 반영되는지 확인할 수 있습니다. 이제 원래 ES|QL 쿼리를 다시 실행해 보겠습니다:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| STATS
    centroid = ST_CENTROID_AGG(location),
    count = COUNT(city_location)
    BY region
| SORT count DESC
| LIMIT 10<p>그러면 공항이 가장 많은 상위 5개 지역과 해당 지역과 일치하는 모든 공항의 중심점, 해당 지역 내 도시 경계를 나타내는 WKT의 길이 범위가 반환됩니다:</p><p>중심</p><p>개수</p><p>지역</p><p>포인트 (-12.139086859300733 31.024386116624648)</p><p>126</p><p>null</p><p>포인트 (-83.10398317873478 42.300230911932886)</p><p>3</p><p>디트로이트</p><p>포인트 (39.74537850357592 47.21613017376512)</p><p>3</p><p>городской округ Батайск</p><p>POINT (-156.80986787192523 20.476673701778054)</p><p>3</p><p>하와이</p><p>포인트 (-73.94515332765877 40.70366442203522)</p><p>3</p><p>뉴욕시</p><p>포인트 (-83.10398317873478 42.300230911932886)</p><p>3</p><p>디트로이트</p><p>포인트 (-76.66873019188643 24.306286952923983)</p><p>2</p><p>새로운 프로비던스</p><p>포인트 (-3.0252167768776417 51.39245774131268)</p><p>2</p><p>카디프</p><p>포인트(-115.40993484668434 32.73126147687435)</p><p>2</p><p>멕시칼리 시</p><p>포인트 (41.790108773857355 50.302146775648)</p><p>2</p><p>Центральный район</p><p>포인트 (-73.88902732171118 45.57078813901171)</p><p>2</p><p>몬트리올</p><p>또한 가장 많이 발견된 지역은 <code>null</code> 입니다. 이것은 무엇을 의미할까요? 이 명령을 SQL의 '왼쪽 조인'에 비유했는데, 이는 공항에 대해 일치하는 도시 경계를 찾을 수 없는 경우 공항이 여전히 반환되지만 <code>airport_city_boundaries</code> 인덱스의 필드에 대한 <code>null</code> 값이 포함된다는 의미입니다. 일치하는 항목이 없는 공항이 125개( <code>city_boundary</code>), 일치하는 항목이 있는 공항이 1개( <code>region</code> 필드 <code>null</code>)인 것으로 나타났습니다. 그 결과 결과에서 <code>region</code> 이 없는 공항이 126개로 집계되었습니다. 사용 사례에서 모든 공항을 도시 경계와 일치시켜야 하는 경우, 빈틈을 메우기 위해 추가 데이터를 소싱해야 합니다. 두 가지를 결정해야 합니다:</p><ul><li><p><code>airport_city_boundaries</code> 인덱스의 레코드에 <code>city_boundary</code> 필드가 없는 경우</p></li><li><p><code>ENRICH</code> 명령을 사용하여 <code>airports</code> 인덱스의 레코드가 일치하지 않는 레코드를 확인합니다(즉. 교차하지 않음)</p></li></ul><h2>Kibana Maps의 위치 기반 정보 데이터에 ES|QL 사용</h2><p>Kibana는 지도 애플리케이션에서 공간 ES|QL에 대한 지원을 추가했습니다. 즉, 이제 ES|QL을 사용해 Elasticsearch에서 위치 기반 정보 데이터를 검색하고 그 결과를 지도에서 시각화할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Kibana 레이어 ES|QL" /><p>레이어 추가 메뉴에 "ES|QL" 이라는 새로운 레이어 옵션이 있습니다. 지금까지 설명한 모든 지리공간 기능과 마찬가지로 "기술 미리보기" 에서 확인할 수 있습니다. 이 옵션을 선택하면 ES|QL 쿼리 결과를 기반으로 맵에 레이어를 추가할 수 있습니다. 예를 들어 전 세계의 모든 공항을 표시하는 레이어를 지도에 추가할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - 공항" /><p>또는 <code>airport_city_boundaries</code> 인덱스의 다각형을 표시하는 레이어를 추가하거나, 각 지역에 몇 개의 공항이 있는지 통계를 생성하는 위의 복잡한 <code>ENRICH</code> 쿼리를 추가하는 것이 더 좋을 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - 지역 통계" /><h2>그 다음은 무엇일까요?</h2><p>이전 <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">위치 기반 정보 검색</a> 블로그에서는 8.14부터 Elasticsearch에서 사용할 수 있는 <code>ST_INTERSECTS</code> 같은 기능을 사용하여 검색을 수행하는 데 중점을 두었습니다. 이 블로그에서는 이러한 검색에 사용한 데이터를 가져오는 방법을 설명합니다. 하지만 Elasticsearch 8.15에는 특히 흥미로운 기능이 추가되었습니다. <code>ST_DISTANCE</code> 효율적인 공간 거리 검색을 수행하는 데 사용할 수 있으며, 다음 블로그의 주제는 이 기능에 관한 것입니다!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/geospatial-data-ingest-for-esql</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/geospatial-data-ingest-for-esql</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 25 Oct 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[ES|QL을 사용한 Elasticsearch 위치 기반 정보 검색]]></title>
    <description><![CDATA[Elasticsearch 쿼리 언어(ES|QL)로 위치 기반 정보 검색. Elasticsearch는 강력한 위치 기반 정보 검색 기능을 갖추고 있으며, 이제 사용 편의성과 OGC 친숙도를 획기적으로 개선하기 위해 ES|QL에 제공됩니다.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch는 수년 동안 강력한 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geospatial-analysis.html">위치 기반 정보 검색 및 분석 기능을</a> 제공해 왔지만, API는 일반적인 GIS 사용자들에게 익숙한 것과는 상당히 달랐습니다. 작년에 저희는 SQL만큼 쉽거나 그보다 더 쉬운 파이프라인 쿼리 언어인 <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">ES|QL 쿼리 언어를 추가했습니다</a>. 특히 Elastic이 탁월한 검색, 보안 및 통합 가시성 사용 사례에 적합합니다. 또한 ES|QL 내에서 지리공간 검색 및 분석에 대한 지원을 추가하여 특히 SQL 또는 <a href="https://en.wikipedia.org/wiki/Geographic_information_system">GIS</a> 커뮤니티에서 온 사용자들이 훨씬 쉽게 사용할 수 있도록 하고 있습니다.</p><p>Elasticsearch 8.12와 8.13은 ES|QL에 위치 기반 정보 유형에 대한 기본 지원을 도입했습니다. 이 기능은 8.14에서 지리공간 검색 기능이 추가되면서 크게 향상되었습니다. 무엇보다도 이 지원은 PostGIS와 같은 다른 공간 데이터베이스에서 사용하는 <a href="https://en.wikipedia.org/wiki/Simple_Features"></a> <a href="https://en.wikipedia.org/wiki/Open_Geospatial_Consortium">오픈 지리공간 컨소시엄(OGC) 의 간단한 기능 액세스 표준을 밀접하게 준수하도록 설계되어 이러한</a> 표준에 익숙한 GIS 전문가가 훨씬 쉽게 사용할 수 있습니다.</p><p>이 블로그에서는 ES|QL을 사용하여 위치 기반 정보 검색을 수행하는 방법과 SQL 및 Query DSL과 비교하는 방법을 보여드리겠습니다. 또한 ES|QL을 사용하여 공간 조인을 수행하는 방법과 Kibana Maps에서 결과를 시각화하는 방법도 보여드리겠습니다. 여기에 설명된 모든 기능은 "기술 미리보기" 에서 확인할 수 있으며, 개선 방법에 대한 피드백을 보내주시면 감사하겠습니다.</p><h2>지리공간 데이터 검색</h2><p>쿼리 예제부터 시작하겠습니다:</p>FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location
<p>이것은 싼야 피닉스 국제공항(SYX) 주변의 직사각형 검색 다각형과 교차하는 모든 도시 경계 다각형을 검색합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3897df6bed5d6061/6a17d7c2abe0f29eccdfe861/e48bac8f246c8842f2ea97ddd54910045262aeb1-1440x808.png" alt="ESQL 지리공간 검색" /><p>공항, 도시 및 도시 경계로 구성된 샘플 데이터 세트에서 이 검색은 교차하는 다각형을 찾아 일치하는 문서에서 원하는 필드를 반환합니다:</p><p>abbrev</p><p>공항</p><p>지역</p><p>도시</p><p>도시_위치</p><p>SYX</p><p>산야 피닉스 인터내셔널</p><p>天涯区</p><p>Sanya</p><p>point(109.5036 18.2533)</p><p>쉬웠습니다! 이제 동일한 쿼리에 대한 기존 Elasticsearch 쿼리 DSL과 비교해 보세요:</p>GET /airport_city_boundaries/_search
{
  "_source": ["abbrev", "airport", "region", "city", "city_location"],
  "query": {
    "geo_shape": {
      "city_boundary": {
        "shape": {
          "type": "polygon",
          "coordinates" : [[
            [109.4, 18.1],
            [109.6, 18.1],
            [109.6, 18.3],
            [109.4, 18.3],
            [109.4, 18.1]
          ]]
        }
      }
    }
  }
}
<p>두 쿼리 모두 의도가 상당히 명확하지만 ES|QL 쿼리는 SQL과 매우 유사합니다. PostGIS에서 동일한 쿼리는 다음과 같습니다:</p>SELECT abbrev, airport, region, city, city_location
FROM airport_city_boundaries
WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
);
<p>ES|QL 예제를 다시 살펴보세요. 비슷하지 않나요?</p>FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location
<p>Elasticsearch API의 기존 사용자들은 ES|QL이 훨씬 더 사용하기 쉽다는 것을 알게 되었습니다. 이제 기존 SQL 사용자, 특히 공간 SQL 사용자는 ES|QL이 익숙한 것과 매우 유사하게 느껴질 것으로 예상합니다.</p><h4>SQL은 왜 안 될까요?</h4><p>Elasticsearch SQL은 어떻습니까? 오래 전부터 사용되어 왔으며 몇 가지 지리 공간적 특징을 가지고 있습니다. 그러나 Elasticsearch SQL은 원래 쿼리 API 위에 래퍼로 작성되었기 때문에 원래 API로 변환할 수 있는 쿼리만 지원되었습니다. ES|QL에는 이러한 제한이 없습니다. 완전히 새로운 스택이기 때문에 SQL에서는 불가능했던 많은 최적화가 가능합니다. 벤치마크 결과 ES|QL은 특히 집계에서 <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/esql/nightly/default/6M">쿼리 API보다 매우 빠른 경우가 많습니다</a>!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18bda964c8b24e36/6a17d7c3e3179155d22d568a/b8b6c2b2e45850d832805ed1e71e522f4955f53c-1440x813.png" alt="다각형-교차-벤치마크" /><h2>SQL과의 차이점</h2><p>이전 예제에서 보듯이 ES|QL은 SQL과 다소 유사하지만 몇 가지 중요한 차이점이 있습니다. 예를 들어 ES|QL은 파이프 쿼리 언어로, FROM과 같은 소스 명령으로 시작한 다음 모든 후속 명령을 파이프 | 문자로 연결합니다. 이렇게 하면 각 명령이 데이터 테이블을 수신하고 해당 테이블에서 필터링( <code>WHERE</code>), 열 추가( <code>EVAL</code>), 집계 수행( <code>STATS</code>) 등의 작업을 수행하는 방식을 매우 쉽게 이해할 수 있습니다. <code>SELECT</code> 로 시작하여 최종 출력 열을 정의하는 대신 하나 이상의 <code>KEEP</code> 명령이 있을 수 있으며, 마지막 명령은 최종 출력 결과를 지정합니다. 이 구조는 쿼리에 대한 추론을 단순화합니다.</p><p>위의 예제에서 <code>WHERE</code> 명령에 초점을 맞추면 PostGIS 예제와 매우 유사하다는 것을 알 수 있습니다:</p><p><em>ES|QL</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
)
<p><em>PostGIS</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
)
<p>문자열 따옴표 문자의 차이 외에도 가장 큰 차이점은 문자열을 공간 유형으로 타입 변환하는 방식에 있습니다. PostGIS에서는 <code>::geometry</code> 접미사를 사용하고, ES|QL에서는 <code>::geo_shape</code> 접미사를 사용합니다. 이는 ES|QL이 Elasticsearch 내에서 실행되고 유형 캐스팅 연산자 <code>::</code> 를 사용하여 문자열을 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#_supported_types">지원되는 ES|QL 유형</a>(이 경우 <code>geo_shape</code>)으로 변환할 수 있기 때문입니다. 또한 Elasticsearch의 <code>geo_shape</code> 및 <code>geo_point</code> 유형은 WGS84로 알려진 공간 좌표계를 의미하며, 더 일반적으로 SRID 번호 4326을 사용하여 참조합니다. PostGIS에서는 명시적이어야 하므로 WKT 문자열에 <code>SRID=4326;</code> 접두사를 사용해야 합니다. 이 접두사를 제거하면 SRID는 0으로 설정되며, 이는 특정 좌표계에 연결되지 않는 Elasticsearch 유형 <code>cartesian_point</code> 및 <code>cartesian_shape</code> 과 유사합니다.</p><p>ES|QL과 PostGIS 모두 유형 변환 함수 구문도 제공합니다:</p><p><em>ES|QL</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    TO_GEOSHAPE("POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))")
)
<p><em>PostGIS</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    ST_SetSRID(
      ST_GeomFromText('POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'),
      4326
    )
)
<h2>OGC 기능</h2><p>Elasticsearch 8.14에는 다음과 같은 네 가지 OGC 공간 검색 기능이 도입되었습니다:</p><p>ES|QL</p><p>PostGIS</p><p>설명</p><p>ST_INTERSECTS</p><p>ST_Intersects</p><p>두 지오메트리가 교차하면 참을 반환하고 그렇지 않으면 거짓을 반환합니다.</p><p>ST_DISJOINT</p><p>ST_Disjoint</p><p>두 지오메트리가 교차하지 않으면 참을 반환하고, 그렇지 않으면 거짓을 반환합니다. ST_INTERSECTS의 역수입니다.</p><p>ST_CONTAINS</p><p>ST_Contains</p><p>하나의 지오메트리에 다른 지오메트리가 포함되어 있으면 참을 반환하고, 그렇지 않으면 거짓을 반환합니다.</p><p>ST_WITHIN</p><p>ST_Within</p><p>하나의 지오메트리가 다른 지오메트리 안에 있으면 참을 반환하고, 그렇지 않으면 거짓을 반환합니다. ST_CONTAINS의 역수입니다.</p><p>이러한 함수는 PostGIS와 유사하게 작동하며 동일한 방식으로 사용됩니다. 예를 들어 <code>ST_INTERSECTS</code> 은 두 지오메트리가 교차하면 참을 반환하고 그렇지 않으면 거짓을 반환합니다. 위 표의 문서 링크를 따라가 보면 모든 ES|QL 예제는 <code>FROM</code> 절 뒤에 <code>WHERE</code> 절 안에 있는 반면, 모든 PostGIS 예제는 리터럴 지오메트리를 사용하고 있음을 알 수 있습니다. 실제로 두 플랫폼 모두 쿼리의 모든 부분에서 해당 함수를 사용할 수 있도록 지원합니다.</p><p><code>ST_INTERSECTS</code> 에 대한 PostGIS 설명서의 첫 번째 예는 다음과 같습니다:</p>SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);
<p>이에 해당하는 ES|QL은 다음과 같습니다:</p>ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)
<p>PostGIS 예제에서 SRID를 지정하지 않은 점에 유의하세요. 이는 PostGIS에서 <code>geometry</code> 유형을 사용할 때 모든 계산이 평면 좌표계에서 수행되므로 두 도형의 SRID가 같으면 SRID가 무엇이든 상관없기 때문입니다. Elasticsearch에서는 대부분의 함수에서도 마찬가지이지만, 다음 블로그에서 공간 거리 검색에 대해 살펴보겠지만 <code>geo_shape</code> 및 <code>geo_point</code> 에서 구형 계산을 사용하는 예외가 있습니다.</p><h2>ES|QL 다용도성</h2><p>위에서 <code>WHERE</code> 절과 <code>ROW</code> 명령에서 공간 함수를 사용하는 예제를 살펴봤습니다. 그 외에는 어디에 의미가 있을까요? 매우 유용한 곳 중 하나는 <code>EVAL</code> 명령어입니다. 이 명령을 사용하면 표현식을 평가하고 결과를 반환할 수 있습니다. 예를 들어 국가 이름으로 그룹화된 모든 공항의 중심이 국가를 나타내는 경계선 내에 있는지 확인해 보겠습니다:</p>FROM airports
| EVAL in_uk = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL in_iceland = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| EVAL within_uk = ST_WITHIN(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL within_iceland = ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| STATS centroid = ST_CENTROID_AGG(location), count=COUNT() BY in_uk, in_iceland, within_uk, within_iceland
| SORT count ASC
<p>결과는 예상대로 영국 공항의 중심이 영국 경계 내에 있고 아이슬란드 경계 내에 있지 않으며 그 반대의 경우도 마찬가지입니다:</p><p>중심</p><p>개수</p><p>in_uk</p><p>in_iceland</p><p>within_uk</p><p>within_iceland</p><p>포인트 (-21.946634463965893 64.13187285885215)</p><p>1</p><p>false</p><p>true</p><p>false</p><p>true</p><p>포인트 (-2.597342072712148 54.33551226578214)</p><p>17</p><p>true</p><p>false</p><p>true</p><p>false</p><p>POINT (0.04453958108176276 23.74658354606057)</p><p>873</p><p>false</p><p>false</p><p>false</p><p>false</p><p>실제로 이러한 함수는 서명이 의미가 있는 쿼리의 모든 부분에서 사용할 수 있습니다. 이 함수는 모두 리터럴 공간 객체 또는 공간 유형의 필드인 두 개의 인수를 받으며, 모두 부울 값을 반환합니다. 한 가지 중요한 고려 사항은 지오메트리의 좌표 참조 시스템(CRS)이 일치해야 하며, 그렇지 않으면 오류가 반환된다는 것입니다. 즉, 동일한 함수 호출에서 <code>geo_shape</code> 유형과 <code>cartesian_shape</code> 유형을 혼합할 수 없습니다. 그러나 <code>geo_point</code> 유형은 <code>geo_shape</code> 유형의 특수한 경우이며 둘 다 동일한 좌표 참조 시스템을 공유하므로 <code>geo_point</code> 유형과 <code>geo_shape</code> 유형을 혼합하여 사용할 수 있습니다. 위에 정의된 각 함수에 대한 문서에는 지원되는 유형 조합이 나열되어 있습니다.</p><p>또한 인수는 공간 리터럴 또는 필드 중 어느 것이든 순서와 상관없이 사용할 수 있습니다. 두 개의 필드, 두 개의 리터럴, 필드와 리터럴 또는 리터럴과 필드를 지정할 수도 있습니다. 유일한 요구 사항은 유형이 호환되어야 한다는 것입니다. 예를 들어, 이 쿼리는 동일한 인덱스에 있는 두 필드를 비교합니다:</p>FROM airport_city_boundaries
| EVAL in_city = ST_INTERSECTS(city_location, city_boundary)
| STATS count=COUNT(*) BY in_city
| SORT count ASC
| EVAL cardinality = CASE(count &lt; 10, "very few", count &lt; 100, "few", "many")
| KEEP cardinality, count, in_city
<p>이 쿼리는 기본적으로 도시 위치가 도시 경계 내에 있는지 묻는데, 일반적으로는 사실이어야 하지만 항상 예외가 있습니다:</p><p>카디널리티</p><p>개수</p><p>in_city</p><p>few</p><p>29</p><p>false</p><p>많은</p><p>740</p><p>true</p><p>훨씬 더 흥미로운 질문은 공항의 위치가 해당 공항이 서비스를 제공하는 도시의 경계 내에 있는지 여부입니다. 그러나 공항 위치는 도시 경계를 포함하는 인덱스와 다른 인덱스에 있습니다. 이를 위해서는 이 두 개의 개별 인덱스에서 데이터를 효과적으로 쿼리하고 상호 연관시킬 수 있는 방법이 필요합니다.</p><h2>공간 조인</h2><p>ES|QL은 <code>JOIN</code> 명령을 지원하지 않지만 SQL의 '왼쪽 조인'과 유사하게 작동하는 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"> 명령을</a> 사용하여 특수한 경우의 조인을 수행할 수 있습니다. 이 명령은 SQL의 'Left 조인'과 유사하게 작동하며, 두 데이터 집합 간의 공간적 관계를 기반으로 한 인덱스의 결과를 다른 인덱스의 데이터로 보강할 수 있습니다.</p><p>예를 들어 공항 위치가 포함된 도시 경계를 찾아서 공항이 취항하는 도시에 대한 추가 정보로 공항 테이블의 결과를 보강한 다음 결과에 대한 몇 가지 통계를 수행해 보겠습니다:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| MV_EXPAND city_boundary
| EVAL boundary_wkt_length = LENGTH(TO_STRING(city_boundary))
| STATS centroid = ST_CENTROID_AGG(location), count = COUNT(city_location), min_wkt = MIN(boundary_wkt_length), max_wkt = MAX(boundary_wkt_length) BY region
| SORT count DESC
| LIMIT 5
<p>그러면 공항이 가장 많은 상위 5개 지역과 해당 지역과 일치하는 모든 공항의 중심점, 해당 지역 내 도시 경계를 나타내는 WKT의 길이 범위가 반환됩니다:</p><p>중심</p><p>개수</p><p>min_wkt</p><p>max_wkt</p><p>지역</p><p>POINT (-32.56093470960719 32.598117914802714)</p><p>90</p><p>207</p><p>207</p><p>null</p><p>포인트 (-73.94515332765877 40.70366442203522)</p><p>9</p><p>438</p><p>438</p><p>뉴욕시</p><p>포인트 (-83.10398317873478 42.300230911932886)</p><p>9</p><p>473</p><p>473</p><p>디트로이트</p><p>POINT (-156.3020245861262 20.176383580081165)</p><p>5</p><p>307</p><p>803</p><p>하와이</p><p>포인트 (-73.88902732171118 45.57078813901171)</p><p>4</p><p>837</p><p>837</p><p>몬트리올</p><p>그렇다면 여기서 실제로 무슨 일이 일어났을까요? <code>JOIN</code> 은 어디에서 발생했나요? 쿼리의 핵심은 <code>ENRICH</code> 명령어에 있습니다:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
<p>이 명령은 <code>airports</code> 인덱스에서 검색된 결과를 보강하고 원본 인덱스의 <code>city_location</code> 필드와 앞서 몇 가지 예제에서 사용한 <code>airport_city_boundaries</code> 인덱스의 <code>city_boundary</code> 필드 간에 <code>intersects</code> 조인을 수행하도록 Elasticsearch에 지시합니다. 그러나 이 정보 중 일부는 이 쿼리에서 명확하게 표시되지 않습니다. 우리가 볼 수 있는 것은 인라이크 정책의 이름 <code>city_boundaries</code> 이며, 누락된 정보는 해당 정책 정의에 캡슐화되어 있습니다.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}
<p>여기에서 <code>geo_match</code> 쿼리를 수행하고(<code>intersects</code> 이 기본값), 일치시킬 필드는 <code>city_boundary</code>, <code>enrich_fields</code> 은 원본 문서에 추가하려는 필드임을 알 수 있습니다. 이러한 필드 중 하나인 <code>region</code> 은 실제로 <code>STATS</code> 명령의 그룹화 키로 사용되었는데, 이 '왼쪽 조인' 기능이 없었다면 불가능했을 것입니다. 인라이크 정책에 대한 자세한 내용은 인라이크 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">문서를</a> 참조하세요. 이러한 문서를 읽다 보면, 수집 파이프라인을 구성하여 인덱스 시점에 데이터를 보강하기 위해 인덱스 보강을 사용하는 방법을 설명하는 것을 볼 수 있습니다. <code>ENRICH</code> 명령은 쿼리 시점에 작동하므로 ES|QL에는 필요하지 않습니다. 필요한 데이터와 보강 정책으로 보강 인덱스를 준비한 다음 ES|QL 쿼리에서 <code>ENRICH</code> 명령을 사용하면 충분합니다.</p><p>또한 가장 많이 발견된 지역은 <code>null</code> 입니다. 이것은 무엇을 의미할까요? 이 명령을 SQL의 '왼쪽 조인'에 비유했는데, 이는 공항에 대해 일치하는 도시 경계를 찾을 수 없는 경우 공항이 여전히 반환되지만 <code>airport_city_boundaries</code> 인덱스의 필드에 대한 <code>null</code> 값이 포함된다는 의미입니다. 일치하는 항목이 없는 공항이 89개( <code>city_boundary</code>), 일치하는 항목이 있는 공항이 1개( <code>region</code> 필드 <code>null</code>)인 것으로 나타났습니다. 그 결과 결과에서 <code>region</code> 이 없는 공항이 90곳으로 집계되었습니다. 또 다른 흥미로운 세부 사항은 <code>MV_EXPAND</code> 명령이 필요하다는 것입니다. 이는 <code>ENRICH</code> 명령이 각 입력 행에 대해 여러 개의 결과를 반환할 수 있고 <code>MV_EXPAND</code> 을 사용하면 이러한 결과를 각 결과마다 하나씩 여러 행으로 분리할 수 있기 때문에 필요합니다. 이는 또한 "하와이" 과 <code>min_wkt</code> 및 <code>max_wkt</code> 결과가 다르게 표시되는 이유를 설명합니다. 이름은 같지만 경계가 다른 여러 지역이 존재하기 때문입니다.</p><h2>Kibana 지도</h2><p>Kibana는 지도 애플리케이션에서 공간 ES|QL에 대한 지원을 추가했습니다. 즉, 이제 ES|QL을 사용해 Elasticsearch에서 위치 기반 정보 데이터를 검색하고 그 결과를 지도에서 시각화할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Kibana 레이어 ES|QL" /><p>레이어 추가 메뉴에 "ES|QL" 이라는 새로운 레이어 옵션이 있습니다. 지금까지 설명한 모든 지리공간 기능과 마찬가지로 "기술 미리보기" 에서 확인할 수 있습니다. 이 옵션을 선택하면 ES|QL 쿼리 결과를 기반으로 맵에 레이어를 추가할 수 있습니다. 예를 들어 전 세계의 모든 공항을 표시하는 레이어를 지도에 추가할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - 공항" /><p>또는 <code>airport_city_boundaries</code> 인덱스의 다각형을 표시하는 레이어를 추가하거나, 각 지역에 몇 개의 공항이 있는지 통계를 생성하는 위의 복잡한 <code>ENRICH</code> 쿼리를 추가하는 것이 더 좋을 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - 지역 통계" /><h2>그 다음은 무엇일까요?</h2><p>위의 두 가지 예제에서 또 다른 공간 함수 <code>ST_CENTROID_AGG</code> 를 압축한 것을 보셨을 것입니다. 이것은 <code>STATS</code> 명령에 사용되는 집계 함수이며, ES|QL에 추가할 예정인 많은 공간 분석 기능 중 첫 번째 기능입니다. 더 많은 것을 보여드릴 수 있게 되면 블로그에 포스팅하겠습니다!</p><p>그 전에 우리가 작업한 특히 흥미로운 기능에 대해 자세히 알려드리고자 합니다. 바로 Elasticsearch에서 가장 많이 사용되는 공간 검색 기능 중 하나인 공간 거리 검색을 수행하는 기능입니다. 거리 검색의 구문이 어떤 모습일지 상상할 수 있나요? OGC 기능과 비슷하지 않을까요? 이 시리즈의 다음 블로그에서 자세히 알아보세요!</p><p>스포일러 경고: Elasticsearch 8.15가 방금 출시되었으며, ES|QL을 사용한 공간 거리 검색이 포함되어 있습니다!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</guid>
    <category><![CDATA[Python]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd05627be20e89dfb/6a17d7c6414c640256944fdb/de886289dcb56494920875303b622b030b9b810f-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 Aug 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>