OpenSearch 쿼리 DSL

OpenSearch 쿼리 DSL

OpenSearch는 쿼리 DSL(Query DSL, domain-specific language)이라는 검색 언어를 제공해요. JSON 인터페이스를 가진 유연한 언어라서, search 요청의 query 파라미터에 쿼리를 지정하면 돼요. 가장 단순한 쿼리 중 하나는 인덱스의 모든 문서를 매칭하는 match_all이에요.

출처: https://docs.opensearch.org/latest/query-dsl/

GET testindex/_search
{
  "query": {
     "match_all": { 
     }
  }
}

쿼리는 여러 쿼리 절(clause)로 구성될 수 있어요. 절을 조합하면 복잡한 쿼리를 만들 수 있고, 크게 리프(leaf) 쿼리와 컴파운드(compound) 쿼리로 나눌 수 있어요.

리프 쿼리 (Leaf queries)

특정 필드에서 값을 검색하는 쿼리예요. 단독으로 쓸 수 있고, 다음과 같은 유형이 있어요.

  • 풀텍스트 쿼리(Full-text queries): 텍스트 문서를 검색해요. 분석된 텍스트 필드를 검색할 때는 인덱싱 시 사용한 것과 같은 분석기로 쿼리 문자열을 검색어로 나눠요. 정확한 값 검색에서는 텍스트 분석을 적용하지 않아요.
  • 용어 수준 쿼리(Term-level queries): ID나 값 범위 같은 정확한 용어를 검색해요. 검색어를 분석하지도 않고 관련도 점수로 정렬하지도 않아요.
  • 지리/xy 쿼리: 지리 데이터를 가진 문서나, 2차원 좌표계의 점·도형을 가진 문서를 검색해요.
  • 조인 쿼리(Joining queries): 중첩 필드나 특정 쿼리에 매칭되는 부모·자식 문서를 검색해요. nested, has_child, has_parent, parent_id 쿼리가 있어요.
  • 스팬 쿼리(Span queries): 정밀한 위치 검색을 해요. 검색어의 순서와 근접성을 제어하는 저수준 쿼리로, 주로 법률 문서 검색에 쓰여요.
  • 특수 쿼리: distance_feature, more_like_this, percolate, rank_feature, script, script_score, wrapper 같은 나머지 쿼리 유형이에요.

컴파운드 쿼리 (Compound queries)

여러 리프·컴파운드 절을 감싸서 결과를 결합하거나 동작을 수정하는 쿼리예요. Boolean, disjunction max, constant score, function score, boosting 쿼리 유형이 포함돼요.

텍스트 필드의 유니코드 특수문자 주의

Unicode 표준 분석기는 특수문자가 포함된 값을 하나의 전체 값으로 인덱싱하지 못해요. 특수문자가 있으면 그 문자를 기준으로 여러 값으로 나뉘어 토큰화돼요. 예를 들어 user.id 값에 하이픈(-)이 있으면, 분석기가 두 사용자를 구분하지 못하고 같은 사용자로 해석할 위험이 있어요.

{
  "bool": {
    "must": {
      "match": {
        "user.id": "User-1"
      }
    }
  }
}

이런 상황을 피하려면 커스텀 분석기를 쓰거나, 정확 매치 검색을 하는 keyword 타입으로 필드를 매핑하면 돼요.

고비용 쿼리 (Expensive queries)

다음 쿼리들은 메모리를 많이 소비해 클러스터 성능을 떨어뜨릴 수 있어요.

  • fuzzy 쿼리
  • prefix 쿼리
  • text·keyword 필드의 range 쿼리
  • regexp 쿼리
  • wildcard 쿼리
  • 내부적으로 prefix 쿼리로 변환되는 query_string 쿼리

고비용 쿼리를 막으려면 search.allow_expensive_queries 클러스터 설정을 끄면 돼요.

PUT _cluster/settings
{
  "persistent": {
    "search.allow_expensive_queries": false
  }
}

더 알아보기