엘라스틱 서치 개발 회고(3)

쿼리 틀

일치하는 Document가 필요한 게 아니라 집계할 특정 field만 필요하므로
query - size : 0 - aggs 으로 구성

GET <인덱스명>/_search
{
  "query": {
    … <쿼리 구문> …
  },
  "size" : 0,
  "aggs": {
    "<임의의 aggregation 1>": {
      "<aggregation 종류>": {
        … <aggreagation 구문> …
      }
    },
    "<임의의 aggregation 2>": {
      "<aggregation 종류>": {
        … <aggreagation 구문> …
      }
    }
  }
}

GET <인덱스명>*/_search?filter_path=aggregations.userIds.buckets.key
  • GET <인덱스명>* : 검색 범위를 userdata-서비스키- 로 시작하는 모든 인덱스로 설정
  • filter_path=aggregations.userIds.buckets.key : filter_path 파라미터를 붙여서 rseponse를 필터링. 콤마를 붙여서 다른 변수 추가 가능

"_source": false
  • _source 필드를 통해 검색된 데이터에서 특정 필드들만 반환 가능. 집계 연산을 제외한 다른 결과는 필요 없으므로 false로 설정

"query": {
    "bool": {
      "filter": [
        {
          "range": {
          }
        },
        {
          "bool": {
            "should": [
              {
                // 생략
              }
            ]
          }
        }
      ]
    }
  }
  • "query": 각 세그먼트마다 쿼리가 다르므로 공통적으로 쓰는 쿼리를 제외하고는 하위 페이지에서 설명
    • "bool": 여러 쿼리를 조합하기 위해서 상위에 bool 쿼리를 사용하고 하위에 다른 쿼리 들을 사용
    • "filter": 쿼리가 참인 도큐먼트를 검색. 스코어를 계산하지 않기 때문에 must보다 검색 속도가 빠르고 캐싱이 가능.
    • "range" : 범위 연산을 할 때 range query 사용. 날짜나 숫자 field에 한해서 사용 가능.

"aggs": {
    "aggIds": {
      "terms": {
        "field": "aggField",
        "size": 100000,
        "include": {
          "partition": 6,
          "num_partitions": 8
        }
      }
    }
  }
  • aggregations은 집계를 의미하며 aggs 필드를 통해 document 개수를 집계. SQL에서 GROUP BY와 유사
  • "aggs” : 집계 연산 시작
    • "aggIds": 집계 결과 이름 설정
    • "terms": terms aggregation 은 keyword 필드의 문자열 별로 버킷을 나누어 집계
    • "field": "aggField.keyword" 집계 기준 필드. keyword를 제외한 다른 타입은 사용 불가
    • "size": 100000 집계 결과 크기
    • "num_partition": 8 전체 파티션 수
    • "partition : 6" : 현재 파티션 인덱스

문자열 검색 구현

문자열 검색 시 “일치” 조건과 “포함할 때” 조건을 구분해서 구현
문자열 검색이 필요한 field의 Type은 text 혹은 keyword인데 상황에 따라 선택

"일치" 쿼리

GET /user*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "terms": {
            "id.keyword": ["grb1" , "grb2"]
          }
        }
      ]
    }
  }
}
  • “일 떄” 조건일 경우에는 keyword 타입 변수를 사용하는데 만약 text 타입 변수를 사용할 경우에는 대소문자 구별이 되지 않는다.
  • 기본 형태소 분석기를 사용하고 있기에 text 타입 변수는 소문자 token으로 쪼개져서 저장된다. 따라서 대문자 검색이 되지 않는다.

"포함" 쿼리


그 외

SQL 쿼리

ES 에서도 일부 sql문이 사용 가능합니다. 쿼리를 sql로 작성할 경우 팀원들이 이해 하기에 쉽겠지만 where in 같이 조금만 쿼리가 복잡해져도 사용이 불가능 하므로 본래 ES 쿼리로 작성하였습니다.

Query
POST _sql?format=txt
{
  "query": """
  SELECT count(distinct cookieId) FROM index
}
------------------------------------------------
Result
count(distinct cookieId)
4617305.0   

Query
POST _sql?format=txt
{
  "query": SELECT count(distinct cookieId) FROM index
  where actionCd = 'PU' and id in 
  (
    SELECT id FROM "userdata-8a4605e5c5d641b7869d9104222a6d38-*"
  where actionCd = 'VC'
    )
}
------------------------------------------------
Result
{
  "error" : {
    "root_cause" : [
      {
        "type" : "parsing_exception",
        "reason" : "line 3:30: IN query not supported yet"
      }
    ],
    "type" : "parsing_exception",
    "reason" : "line 3:30: IN query not supported yet"
  },
  "status" : 400
}

Scroll API

RDBMS의 cursor를 사용하는 것과 유사하다. scrollID는 고정되어있고 scrollId로 Search요청을 보낼 때마다 다른 데이터를 받을 수 있습니다.
기존에는 10,000개 이상의 document들에 대해 페이징을 적용할 때 scroll api를 사용하는 것이 권장되었지만 7 버전이 되면서부터 더이상 권장하지 않습니다. (We no longer recommend using the scroll API for deep pagination. If you need to preserve the index state while paging through more than 10,000 hits, use the search_after parameter with a point in time)
aggregation을 사용하는 것보다 빠르지도 않고 공식적으로 사용을 권장하지 않는다고 하니 사용 중단.

GET /user*/_search?scroll=1m
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "regDtm": {
              "gte": "2021-01-02T00:00:00.000Z",
              "lte": "2021-12-03T23:59:59.000Z"
            }
          }
        }
      ]
    }
  },
  "size": 100
}

//  첫 request에서 받은 scroll_id 로 계속 받아올 수 있다.
GET _search/scroll?scroll_id=DnF1ZXJ5VGhlbkZldGNoAwAAAAAAl4uhFmJ2VGN1ekZqUUtTeFk1bXdLQTZFTEEAAAAAAJKm9BZ4VWo3azBsdVRXQ01JOWpJSjJ1OXhRAAAAAAAKk3AWcUxpVHFFVXZUQUdaMEZLMWhwQUtuUQ==
{
}

좋은 웹페이지 즐겨찾기