반응형
Query DSL( Domain Specific Language )
json 포맷으로 query를 만들어서 검색을 해보는 Query DSL에 대해 알아보겠습니다.
물론 SQL 문으로 검색할수도 있지만, elastic에서는 검색할 때 대부분 Query DSL을 사용하므로 이 방법을 익혀두는 것이 좋습니다.
앞으로 소개 할 query 절은 Query Context 또는 Filter Context에서 사용되는지 여부에 따라 다르게 동작합니다.
- Query Context: "해당 document가 query 절과 얼마나 잘 일치하는가?"라는 질문에 응답하는데, document가 얼마나 잘 일치하는지를 _score( 관련성 점수, relevance score )로 표현합니다.
- Filter Context: "해당 docuemnt가 query 절과 일치합니까?"라는 질문에 응답하는데, 그 대답은 true 또는 false이며 점수는 계산하지 않습니다.
Query VS Filter Context 예제
아래의 예제는 다음의 종족이 모두 충족되는 document를 반한하는 예제입니다.
- title 필드에 search가 있고
- content 필드에 elasticsearch가 있고
- status 필드의 값이 정확히 published이고
- publish_date 필드의 값이 정확히 2015-01-01 이후인 경우
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
Query DSL 예제
이제 예제를 통해 Query DSL에는 어떤 것들이 있는지 살펴보도록 하겠습니다.
ElasticSearch의 모든 API를 소개하는 것은 무리가 있으며, 아래와 같이 몇 가지의 사용법을 익힌다면 문서를 보면서 자유자재로 사용할 수 있지 않을까 싶습니다.
전체 데이터 검색 (쿼리)
<index> 내 모든 데이터 (Max size: 10,000)
- match_all 쿼리는 지정된 index의 모든 document를 검색하는 방법입니다.
- 즉, 특별한 검색어 없이 모든 document를 가져오고 싶을 때 사용합니다.
GET $index/_search
{
"query": {
"match_all": {}
}
}
<index> 내 모든 데이터 (10,000 개 이상의 데이터)
GET $index/_search?scroll=1m
{
"query": {
"match_all": {}
}
}
이후 해당 쿼리로 나온 “scroll_id“를 다음 쿼리에 넣어주면 다음 1000개의 데이터를 뽑을 수 있다.
POST /_search/scroll
{
"scroll" : "1m",
"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFnpTYVVRVmN4UV91V0xuNHBXamVOZmcAAAAAAAABSRZlYldUMmxaeVNLMnVDQXVSNzdqN3V3"
}
특정 데이터 검색 (쿼리)
들어가기 전에
- mapping정보를 입력하지 않은 index에는 PUT /$index/$type/$id와 같이 데이터 입력이 가능합니다.
- 하지만 mapping정보까지 입력한 index에 데이터 입력시 에러가 발생할 수 있습니다.
- Elasticsearch 6.0부터는 하나의 type만 지원되기 때문에 이후 데이터 입력시 /$index/_doc/$id로 해야합니다.
- 특정 "field_name"을 검색할 시, 모두 계층형(hierarchy) 구조로 작성해야하며 배열의 경우에도 일반적으로(.) 접근하면 됩니다.
- e.g. "field": "path.to.field.field_name"
- 계층형(hierarchy) 구조 중 "to"가 배열이라고 가정하더라도, 일반적으로 .을 사용하여 접근하면 됩니다.
특정 필드 내 특정 아이디를 가진 mbr 찾기
GET $index/_doc/$id
특정 값을 갖는 데이터 찾기
- match 쿼리는 기본 필드 검색 쿼리로써, 텍스트/숫자/날짜를 허용합니다.
GET $index/_search
{
"query": {
"match" : {
"field_name" : "value"
}
}
}
특정 필드의 데이터를 찾기
- 특정 index의 데이터 중 “field_name1”, “field_name2” 필드 데이터를 보고 싶다면?
GET $index/_search
{
"_source": ["field_name1", "field_name2"],
"query": {
"match_all": {}
}
}
특정 필드가 포함된 데이터 찾기
- 특정 필드가 포함되지 않은 필드를 찾고싶다면? "must" → "must_not"
- + should: bool should 절에 지정된 모든 쿼리 중 하나라도 일치하는 document를 조회
GET $index/_search
{
"query": {
"bool": {
"must": [
{
"exists": {
"field": "field_name"
}
}
]
}
}
}
특정 필드에 특정 문자열을 포함하는 데이터 찾기
GET $index/_search?scroll=1m
{
"query": {
"bool": {
"must": [
{
"query_string": {
"query": "*sub-string*",
"fields": [
"field_name"
]
}
}
]
}
}
}
특정 범위에 해당하는 데이터 찾기
- range 쿼리는 정수, 날짜 등 범위를 지정하여 범위에 해당하는 값을 갖는 document를 조회합니다.
- time type: epochmiltime, epochtime
GET $index/_search
{
"query": {
"range": {
"time": {
"gte": "2022-08-00 00:00:00.000",
"lte": "2022-08-06 23:59:59.999",
"format": "yyyy-MM-dd HH:mm:ss.SSS",
"time_zone": "+09:00"
}
}
}
}
- range에서의 key 값 정리
- "gt" – greater than
- "gte" – greater than or equal to
- "lt" – less than
- "lte" – less than or equal to
특정 field가 regexp에 해당되는 값 찾기
- regexp 쿼리는 정규표현식에 해당하는 값을 갖는 document를 조회합니다.
{
"query": {
"regexp":{
"field_name": ".*street"
}
}
}
검색 결과를 특정 field로 aggregate하여 각 개수를 확인하기
{
"query": {
"bool": {
"must": [
{
"query_string": {
"query": "*검색어*",
"fields": [
"필드명1",
"필드명2",
"필드명3"
]
}
}
]
}
},
"aggs": {
"my_aggregate_result": {
"terms": {
"field": "aggregate할 필드명"
}
}
}
}
검색 결과 top_hits 사용
네이버처럼 블로그, 지식인, 카페별 검색 결과를 출력할 때 유용할 것 같다.
GET /$index/_doc/_search
{
"size": 0,
"query": {
"bool": {
"must": {
"query_string": {
"query": "*검색어*",
"fields": [
"필드명"
]
}
}
}
},
"aggs": {
"top_tags": {
"terms": {
"field": "그룹핑 할 필드명",
"size": 5 // 그룹핑 한 결과 개수
},
"aggs": {
"my_top_hits": {
"top_hits": {
"size": 5, // 그룹별 개수
"_source": { // 출력할 내용을 필터링하고 싶으면 `_source`를 추가한다.
"includes": [
"type",
"title"
]
}
}
}
}
}
}
}
데이터 삭제 (쿼리)
특정 id의 데이터 삭제
- DELETE <index>/_doc/<id> 형태
DELETE $index/_doc/$id
인덱스 내에 document 전체 삭제
- 특정 쿼리에 해당하는 데이터 삭제하기 위해서는 "query" 내에 퀴리문을 작성해야 합니다.
- return: 쿼리로 삭제된 데이터의 갯수..
POST $index/_doc/_delete_by_query
{
"query": {
"match_all": {}
}
}
DELETE /$index/_doc/_query
{
"query": {
"match_all": {}
}
}
인덱스 내 특정 필드 삭제
POST /$index/_doc/_update_by_query
{
"script" : "ctx._source.remove('필드명')",
"query" : {
"exists": { "field": "필드명" }
}
}
참고
- 개발 Elasticsearch 기본 쿼리: https://hodolman.com/33
- [Elastic] Query DSL: https://victorydntmd.tistory.com/314
반응형