https://docs.opensearch.org/latest/getting-started/search-data/
OpenSearch에서는 데이터를 검색하는 여러 가지 방법이 있습니다:
이 튜토리얼에는 쿼리 문자열 쿼리와 쿼리 DSL을 사용한 검색에 대한 간단한 소개가 포함되어 있습니다.
이 튜토리얼을 위해 아직 학생 데이터를 인덱싱하지 않았다면 인덱싱해야 합니다. students 인덱스를 삭제(DELETE /students)한 다음 다음 일괄 요청을 보내는 것으로 시작할 수 있습니다:
POST _bulk
{ "create": { "_index": "students", "_id": "1" } }
{ "name": "John Doe", "gpa": 3.89, "grad_year": 2022}
{ "create": { "_index": "students", "_id": "2" } }
{ "name": "Jonathan Powers", "gpa": 3.85, "grad_year": 2025 }
{ "create": { "_index": "students", "_id": "3" } }
{ "name": "Jane Doe", "gpa": 3.52, "grad_year": 2024 }
인덱스의 모든 문서를 검색하려면 다음 요청을 보내세요:
GET /students/_search
앞의 요청은 인덱스의 모든 문서와 일치하는 match_all 쿼리와 동일합니다:
GET /students/_search
{
"query": {
"match_all": {}
}
}
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
_shards
_shards 객체는 쿼리가 실행된 총 샤드 수와 성공하거나 실패한 샤드 수를 지정합니다. 샤드 자체와 모든 레플리카를 사용할 수 없는 경우 샤드가 실패할 수 있습니다. 관련 샤드 중 하나라도 실패하면 OpenSearch는 나머지 샤드에서 쿼리를 계속 실행합니다.
hits
hits 객체는 일치하는 문서의 총 수와 문서 자체(hits 배열에 나열됨)를 포함합니다. 일치하는 각 문서는 _index 및 _id 필드와 완전히 원본 인덱싱된 문서를 포함하는 _source 필드를 포함합니다.
각 문서는 _score 필드에서 관련성 점수를 받습니다. match_all 검색을 실행했기 때문에 모든 문서 점수는 1로 설정됩니다(관련성에 차이가 없음). max_score 필드에는 일치하는 문서의 가장 높은 점수가 포함됩니다.
쿼리 문자열 쿼리는 가볍지만 강력합니다. 쿼리 문자열 쿼리를 q 쿼리 매개변수로 보낼 수 있습니다. 예를 들어, 다음 쿼리는 이름이 john인 학생을 검색합니다:
GET /students/_search?q=name:john
OpenSearch는 일치하는 문서를 반환합니다:
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.9808291,
"hits": [
{
"_index": "students",
"_id": "1",
"_score": 0.9808291,
"_source": {
"name": "John Doe",
"gpa": 3.89,
"grad_year": 2022
}
}
]
}
}
쿼리 문자열 구문에 대한 자세한 정보는 "쿼리 문자열 쿼리 언어"를 참조하세요.
쿼리 DSL을 사용하면 더 복잡하고 사용자 정의된 쿼리를 만들 수 있습니다.
text로 매핑된 필드에서 전체 텍스트 검색을 실행할 수 있습니다. 기본적으로 텍스트 필드는 기본 분석기에 의해 분석됩니다. 분석기는 텍스트를 용어로 분할하고 소문자로 변경합니다. OpenSearch 분석기에 대한 자세한 정보는 "분석기"를 참조하세요.
예를 들어, 다음 쿼리는 이름이 john인 학생을 검색합니다:
GET /students/_search
{
"query": {
"match": {
"name": "john"
}
}
}
응답에는 일치하는 문서가 포함됩니다:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.9808291,
"hits": [
{
"_index": "students",
"_id": "1",
"_score": 0.9808291,
"_source": {
"name": "John Doe",
"gpa": 3.89,
"grad_year": 2022
}
}
]
}
}
쿼리 텍스트는 소문자이지만 필드의 텍스트는 그렇지 않지만, 쿼리는 여전히 일치하는 문서를 반환한다는 점에 주목하세요.
검색 문자열에서 용어를 재배열할 수 있습니다. 예를 들어, 다음 쿼리는 "doe john"을 검색합니다:
GET /students/_search
{
"query": {
"match": {
"name": "doe john"
}
}
}
응답에는 두 개의 일치하는 문서가 포함됩니다:
{
"took": 14,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.4508327,
"hits": [
{
"_index": "students",
"_id": "1",
"_score": 1.4508327,
"_source": {
"name": "John Doe",
"gpa": 3.89,
"grad_year": 2022
}
},
{
"_index": "students",
"_id": "3",
"_score": 0.4700036,
"_source": {
"name": "Jane Doe",
"gpa": 3.52,
"grad_year": 2024
}
}
]
}
}
match 쿼리 유형은 기본적으로 OR를 연산자로 사용하므로 쿼리는 기능적으로 "doe OR john"입니다. John Doe와 Jane Doe 모두 "doe"라는 단어와 일치했지만, John Doe는 "john"과도 일치했기 때문에 더 높은 점수를 받았습니다.
name 필드에는 OpenSearch에서 자동으로 추가하는 name.keyword 하위 필드가 포함되어 있습니다. 이전 요청과 유사한 방식으로 name.keyword 필드를 검색하면:
GET /students/_search
{
"query": {
"match": {
"name.keyword": "john"
}
}
}
키워드 필드는 정확히 일치해야 하므로 요청은 히트를 반환하지 않습니다.
그러나 정확한 텍스트 "John Doe"를 검색하면:
GET /students/_search
{
"query": {
"match": {
"name.keyword": "John Doe"
}
}
}
OpenSearch는 일치하는 문서를 반환합니다:
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.9808291,
"hits": [
{
"_index": "students",
"_id": "1",
"_score": 0.9808291,
"_source": {
"name": "John Doe",
"gpa": 3.89,
"grad_year": 2022
}
}
]
}
}
Boolean 쿼리를 사용하여 정확한 값을 가진 필드에 대한 filter 절을 쿼리에 추가할 수 있습니다.
Term 필터는 특정 용어와 일치합니다. 예를 들어, 다음 Boolean 쿼리는 졸업년도가 2022인 학생을 검색합니다:
GET students/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "grad_year": 2022 }}
]
}
}
}
Range 필터를 사용하면 값의 범위를 지정할 수 있습니다. 예를 들어, 다음 Boolean 쿼리는 GPA가 3.6보다 큰 학생을 검색합니다:
GET students/_search
{
"query": {
"bool": {
"filter": [
{ "range": { "gpa": { "gt": 3.6 }}}
]
}
}
}
필터에 대한 자세한 정보는 "쿼리 및 필터 컨텍스트"를 참조하세요.
복합 쿼리를 사용하면 여러 쿼리나 필터 절을 결합할 수 있습니다. Boolean 쿼리는 복합 쿼리의 예입니다.
예를 들어, 이름이 "doe"와 일치하는 학생을 검색하고 졸업년도와 GPA로 필터링하려면 다음 요청을 사용하세요:
GET students/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "doe"
}
},
{ "range": { "gpa": { "gte": 3.6, "lte": 3.9 } } },
{ "term": { "grad_year": 2022 }}
]
}
}
}
Boolean 및 기타 복합 쿼리에 대한 자세한 정보는 "복합 쿼리"를 참조하세요.
이 튜토리얼에서 설명한 기존 전체 텍스트 검색과 함께 OpenSearch는 k-NN, 의미론적, 다중모달, 희소, 하이브리드, 대화형 검색을 포함한 다양한 기계 학습(ML) 기반 검색 방법을 지원합니다. OpenSearch에서 지원하는 모든 검색 방법에 대한 정보는 "검색"을 참조하세요.
OpenSearch 데이터 검색에 대한 문서를 한국어로 번역해드리겠습니다.검색 가이드 번역이 완료되었습니다! 이제 이 문서도 쿡북 형태로 활용할 수 있도록 몇 가지 제안드리겠습니다:
1. 검색 유형별 선택 가이드:
## 언제 어떤 검색을 사용할까?
### 간단한 키워드 검색
→ 쿼리 문자열: `?q=name:john`
### 유연한 텍스트 검색
→ match 쿼리: 오타 허용, 순서 무관
### 정확한 일치 검색
→ keyword 필드: 대소문자, 띄어쓰기 정확히 일치
### 숫자/날짜 범위 검색
→ range 필터: `"gte": 3.6, "lte": 3.9`
### 복합 조건 검색
→ bool 쿼리: must/should/filter 조합
2. 자주 사용하는 쿼리 패턴:
## 실무에서 자주 쓰는 패턴
### 기본 검색
- 전체 조회: `GET /인덱스/_search`
- 특정 필드: `GET /인덱스/_search?q=필드:값`
### 필터링 조합
- AND 조건: bool.must 사용
- OR 조건: bool.should 사용
- 제외 조건: bool.must_not 사용
### 성능 최적화
- 필터 우선: filter는 캐시됨
- 정확한 매칭: keyword 필드 활용
- 시간 초과: ?timeout=30s 설정
3. 점수 이해하기:
## 검색 점수(_score) 해석
### 점수가 높을수록 관련성 높음
- match_all: 모든 문서 1.0
- 키워드 일치: 빈도에 따라 변동
- 여러 조건: 조건별 점수 합산
### 점수에 영향을 주는 요소
1. 단어 빈도 (TF)
2. 역문서 빈도 (IDF)
3. 문서 길이 정규화