본문 바로가기
WIKI 기술 지식 베이스

Search your data

원문 보기 위키 갱신

출처: 문서

본문

데이터 검색하기

OpenSearch 검색은 OpenSearch의 기본 쿼리 언어인 query domain-specific language (DSL)를 기반으로 해요. 이 언어를 사용하면 복잡하고 완전히 커스터마이징 가능한 쿼리를 만들 수 있어요. 대안인 query string query language는 검색 요청의 쿼리 파라미터에서 사용할 수 있는 간소화된 언어예요. 이 튜토리얼에서는 query string 쿼리와 query DSL을 사용한 검색을 간략하게 소개해요. 예제에서는 Ingest your data into OpenSearch에서 만든 students 인덱스를 쿼리해요.

이 튜토리얼의 검색은 쿼리에 담긴 텍스트를 문서에 저장된 텍스트와 대조해 매칭해요. OpenSearch는 정확한 단어가 아니라 의미를 매칭하는 벡터 검색도 지원해요. 자세한 내용은 Vector search를 참고하세요.

인덱스의 모든 문서 가져오기

인덱스의 모든 문서를 가져오려면 다음 요청을 보내세요:

GET /students/_search

{% include copy-curl.html %}

앞의 요청은 인덱스의 모든 문서와 매칭되는 match_all 쿼리와 동일해요:

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

{% include copy-curl.html %}

OpenSearch는 매칭되는 문서를 반환해요:

{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 1,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      },
      {
        "_index": "students",
        "_id": "2",
        "_score": 1,
        "_source": {
          "name": "Jonathan Powers",
          "gpa": 3.85,
          "grad_year": 2025
        }
      },
      {
        "_index": "students",
        "_id": "3",
        "_score": 1,
        "_source": {
          "name": "Jane Doe",
          "gpa": 3.52,
          "grad_year": 2024
        }
      }
    ]
  }
}

응답 본문 필드

앞의 응답에는 다음 필드가 포함되어 있어요.

took

took 필드에는 쿼리 실행에 걸린 시간이 밀리초 단위로 들어 있어요.

timed_out

이 필드는 요청이 시간 초과됐는지 여부를 나타내요. 요청이 시간 초과되면 OpenSearch는 시간 초과 전까지 수집된 결과를 반환해요. timeout 쿼리 파라미터를 지정해 원하는 시간 초과 값을 설정할 수 있어요:

GET /students/_search?timeout=20ms

{% include copy-curl.html %}

_shards

_shards 객체는 쿼리가 실행된 샤드의 총 개수와 성공하거나 실패한 샤드의 개수를 나타내요. 샤드 자체와 모든 복제본을 사용할 수 없으면 샤드가 실패할 수 있어요. 관련된 샤드 중 하나라도 실패하면 OpenSearch는 나머지 샤드에서 쿼리 실행을 계속해요.

hits

hits 객체에는 매칭되는 문서의 총 개수와 문서 그 자체(hits 배열에 나열됨)가 들어 있어요. 매칭되는 각 문서에는 _index와 _id 필드, 그리고 처음 인덱싱된 문서 전체가 담긴 _source 필드가 포함되어 있어요.

각 문서에는 _score 필드에 관련성 점수가 매겨져요. match_all 검색을 실행했기 때문에 모든 문서 점수는 1로 설정돼요(관련성에 차이가 없어요). max_score 필드에는 매칭되는 문서 중 가장 높은 점수가 들어 있어요.

Query string 쿼리

query string 쿼리는 q 쿼리 파라미터로 보낼 수 있어요. 예를 들어 다음 쿼리는 이름이 john인 학생을 검색해요:

GET /students/_search?q=name:john

{% include copy-curl.html %}

OpenSearch는 매칭되는 문서를 반환해요:

{
  "took": 18,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.44583148,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 0.44583148,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      }
    ]
  }
}

query string 문법에 대한 자세한 내용은 Query string query language를 참고하세요.

Query DSL

Query DSL을 사용하면 더 복잡하고 커스터마이징된 쿼리를 만들 수 있어요.

전문 검색

text로 매핑된 필드에 대해 전문 검색을 실행할 수 있어요. 기본적으로 텍스트 필드는 default 분석기로 분석돼요. 분석기는 텍스트를 텀으로 나누고 소문자로 바꿔요. OpenSearch 분석기에 대한 자세한 내용은 Analyzers를 참고하세요.

OpenSearch가 필드에 저장하는 텀을 보려면 Analyze API를 사용하세요. 다음 요청은 name 필드에 구성된 분석기를 사용해 John Doe 텍스트를 분석해요:

GET /students/_analyze
{
  "field": "name",
  "text": "John Doe"
}

{% include copy-curl.html %}

응답에는 텀마다 토큰이 하나씩 포함되어 있어요:

{
  "tokens": [
    {
      "token": "john",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "doe",
      "start_offset": 5,
      "end_offset": 8,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

OpenSearch는 john과 doe 텀을 모두 소문자로 저장해요. match 쿼리도 쿼리 텍스트를 같은 방식으로 분석하기 때문에 John, john, JOHN은 모두 john이라는 텀을 만들어 이 문서와 매칭돼요.

예를 들어 다음 쿼리는 이름이 john인 학생을 검색해요:

GET /students/_search
{
  "query": {
    "match": {
      "name": "john"
    }
  }
}

{% include copy-curl.html %}

응답에는 매칭되는 문서가 포함되어 있어요:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.44583148,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 0.44583148,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      }
    ]
  }
}

쿼리 텍스트는 소문자인 반면 필드의 텍스트는 소문자가 아니라는 점에 주목하세요. 그럼에도 쿼리는 매칭되는 문서를 반환해요.

검색 문자열에서 텀 순서를 바꿀 수도 있어요. 예를 들어 다음 쿼리는 doe john을 검색해요:

GET /students/_search
{
  "query": {
    "match": {
      "name": "doe john"
    }
  }
}

{% include copy-curl.html %}

응답에는 매칭되는 문서 두 개가 포함되어 있어요:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.6594695,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 0.6594695,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      },
      {
        "_index": "students",
        "_id": "3",
        "_score": 0.21363801,
        "_source": {
          "name": "Jane Doe",
          "gpa": 3.52,
          "grad_year": 2024
        }
      }
    ]
  }
}

match 쿼리 타입은 기본적으로 OR을 연산자로 사용하기 때문에 이 쿼리는 기능적으로 doe OR john이에요. John Doe와 Jane Doe 둘 다 doe라는 단어와 매칭되지만, John Doe는 john도 매칭되기 때문에 더 높은 점수를 받아요. OpenSearch가 이런 점수를 계산하는 방식에 대한 설명은 Relevance를 참고하세요.

모든 텀이 매칭되도록 요구하기

쿼리 텀을 모두 포함하는 문서만 반환하려면 operator를 and로 설정하세요:

GET /students/_search
{
  "query": {
    "match": {
      "name": {
        "query": "doe john",
        "operator": "and"
      }
    }
  }
}

{% include copy-curl.html %}

응답에는 두 텀을 모두 포함하는 유일한 문서인 John Doe만 포함되어 있어요:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.6594695,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 0.6594695,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      }
    ]
  }
}

구문 매칭

match 쿼리는 텀의 순서를 무시해요. 텀이 주어진 순서 그대로 서로 붙어 나타나도록 요구하려면 match_phrase 쿼리를 사용하세요:

GET /students/_search
{
  "query": {
    "match_phrase": {
      "name": "john doe"
    }
  }
}

{% include copy-curl.html %}

응답에는 매칭되는 문서가 포함되어 있어요:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.6594694,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 0.6594694,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      }
    ]
  }
}

같은 쿼리로 doe john을 검색하면 텀이 필드에서 반대 순서로 나타나기 때문에 결과가 반환되지 않아요.

자세한 내용은 Match phrase query를 참고하세요.

철자가 틀린 단어 매칭

지금까지의 쿼리는 쿼리 텀이 저장된 텀과 정확히 일치해야 해요. 인덱스에 john이 있는데도 jhon을 검색하면 결과가 반환되지 않아요:

GET /students/_search
{
  "query": {
    "match": {
      "name": "jhon"
    }
  }
}

{% include copy-curl.html %}

비슷하게 철자된 텀을 매칭하려면, 매칭을 찾을 때 OpenSearch가 쿼리 텀에 허용하는 단일 문자 변경 횟수를 fuzziness에 설정하세요. 여기서 변경이란 삽입, 삭제, 치환, 또는 인접한 두 문자의 위치 바꾸기를 말해요. 이 숫자를 _편집 거리(edit distance)_라고 해요. jhon을 john으로 바꾸려면 h와 o의 위치를 서로 바꿔야 하므로 편집 거리 1이면 충분해요:

GET /students/_search
{
  "query": {
    "match": {
      "name": {
        "query": "jhon",
        "fuzziness": 1
      }
    }
  }
}

{% include copy-curl.html %}

응답에는 매칭되는 문서가 포함되어 있어요. OpenSearch가 퍼지 매칭에 페널티를 부과하기 때문에 이 점수는 john이 정확히 매칭됐을 때의 점수보다 낮아요:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.3343736,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 0.3343736,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      }
    ]
  }
}

fuzziness를 AUTO로 설정하면 OpenSearch가 쿼리 텀 길이에 따라 편집 거리를 알아서 선택하기 때문에 관련 없는 짧은 단어가 매칭되는 것을 막을 수 있어요. 자세한 내용은 Fuzziness를 참고하세요.

키워드 검색

Ingest data의 bulk 요청을 통해 OpenSearch가 필드 타입을 추론하도록 했기 때문에, name 필드에는 OpenSearch가 자동으로 추가한 name.keyword 서브필드가 있어요. 이전 요청과 비슷한 방식으로 name.keyword 필드를 검색해 보세요:

GET /students/_search
{
  "query": {
    "match": {
      "name.keyword": "john"
    }
  }
}

{% include copy-curl.html %}

keyword 필드는 정확히 일치해야 하기 때문에 이 요청은 결과를 반환하지 않아요.

이제 정확한 텍스트 John Doe를 검색해 보세요:

GET /students/_search
{
  "query": {
    "match": {
      "name.keyword": "John Doe"
    }
  }
}

{% include copy-curl.html %}

OpenSearch는 매칭되는 문서를 반환해요:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_score": 1,
        "_source": {
          "name": "John Doe",
          "gpa": 3.89,
          "grad_year": 2022
        }
      }
    ]
  }
}

필터

Boolean 쿼리를 사용하면 정확한 값을 가진 필드를 대상으로 쿼리에 필터 절을 추가할 수 있어요.

텀 필터는 특정 텀과 매칭돼요. 예를 들어 다음 Boolean 쿼리는 졸업 연도가 2022년인 학생을 검색해요:

GET /students/_search
{
  "query": { 
    "bool": { 
      "filter": [ 
        { "term":  { "grad_year": 2022 }}
      ]
    }
  }
}

{% include copy-curl.html %}

범위 필터를 사용하면 값의 범위를 지정할 수 있어요. 예를 들어 다음 Boolean 쿼리는 GPA가 3.6보다 큰 학생을 검색해요:

GET /students/_search
{
  "query": { 
    "bool": { 
      "filter": [ 
        { "range": { "gpa": { "gt": 3.6 }}}
      ]
    }
  }
}

{% include copy-curl.html %}

필터에 대한 자세한 내용은 Query and filter context를 참고하세요.

복합 쿼리

복합 쿼리를 사용하면 여러 개의 쿼리 절이나 필터 절을 결합할 수 있어요. Boolean 쿼리가 복합 쿼리의 한 예예요.

예를 들어 이름이 doe와 매칭되는 학생을 검색하면서 졸업 연도와 GPA로 필터링하려면 다음 요청을 사용하세요:

GET /students/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "doe"
          }
        },
        { "range": { "gpa": { "gte": 3.6, "lte": 3.9 } } },
        { "term":  { "grad_year": 2022 }}
      ]
    }
  }
}

{% include copy-curl.html %}

Boolean 쿼리와 기타 복합 쿼리에 대한 자세한 내용은 Compound queries를 참고하세요.

기타 쿼리 언어

query DSL과 query string 쿼리 외에도 OpenSearch는 다음 쿼리 언어를

더 알아보기 (Learn more)