Elasticsearch - 2

김상훈·2024년 6월 16일

Elasticsearch

목록 보기
2/2

엘라스틱서치 공식문서

Filter Context 검색

  • 검색에서 여러 쿼리를 조합하기 위해서는 상위에 bool 쿼리를 사용하고 그 안에 다른 쿼리들을 넣는 식으로 사용이 가능함
  • bool 쿼리는 다음과 같이 4개의 인자를 가지고 있으며, filter의 경우만 score 계산을 하지 않는 Filter Context에 해당됨

bool

  • must: bool must 절에 지정된 모든 쿼리가 일치하는 document를 조회
  • should: bool should 절에 지정된 모든 쿼리 중 하나라도 일치하는 document를 조회
  • must_not: bool must_not 절에 지정된 모든 쿼리가 모두 일치하지 않는 document를 조회
  • filter: 쿼리가 참인 document를 검색하지만 score를 계산하지 않음
    • must 보다 검색 속도가 빠르고 캐싱이 가능함

풀 텍스트 검색은 스코어 점수 기반으로 relevancy가 높은 결과부터 가져옴

이와 상반되는 특성을 Exact Value 라고 하는데, 값이 정확히 일치 하는지의 여부 만을 따지는 검색임

Exact Value에는 term, terms, range와 같은 쿼리들이 이 부분에 속하며, 스코어를 계산하지 않기 때문에 보통 bool 쿼리의 filter 내부에서 사용됨

  • bool 쿼리 내에 위의 각 절들을 조합해서 사용할 수 있음
```
[GET] my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { <쿼리> }, …
      ],
      "must_not": [
        { <쿼리> }, …
      ],
      "should": [
        { <쿼리> }, …
      ],
      "filter": [
        { <쿼리> }, …
      ]
    }
  }
}
```
  • 주소가 rlatkd이지만, 과일이 banana가 아닌 document를 조회
    {
      "query": {
        "bool": {
          "must": [
            { "match": { "address": "rlatkd" } }
          ],
          "must_not": [
            { "match": { "fruit": "banana" } }
          ]
        }
      }
    }
  • bool 쿼리의 should 는 검색 점수(score)를 조정하기 위해 사용할 수 있음
  • address가 ‘rlatkd’을 포함하는 도큐먼트를 검색하는데 그 결과들 중 ‘banana’ 가 포함된 결과에 가중치를 줘서 상위로 올리고 싶으면 should 안에 찾는 검색을 추가 하면됨
      "query": {
        "bool": {
          "must": [
            {"match": {
              "address": "rlatkd"
            }}
          ],
          "should": [
            {"match": {
              "address": "banana"
            }}
          ]
        }
      }

filter

  • filter 쿼리는 document가 검색 쿼리와 일치하는지 나타내는 _score 값을 계산하지 않도록 쿼리 실행을 최적화 함
  • bool 쿼리의 filter 안에 하위 쿼리를 사용하면 스코어에 영향을 주지 않음
  • filter 안에 넣은 검색 조건들은 스코어를 계산하지 않지만 캐싱이 되기 때문에 쿼리가 더 가볍고 빠르게 실행됨
  • 문자열 데이터는 keyword 형식으로 저장하여 정확한 검색이 가능함
  • 문자열과 공백, 대소문자까지 정확히 일치하는 데이터만을 결과로 리턴함
    "query": {
        "bool": {
          "filter": {"term":{
            "address.keyword":"rlatkd banana"
          }}
        }
      }
  • keyword 타입으로 저장된 필드는 스코어를 계산하지 않고 정확값의 일치 여부만을 따지기 때문에 스코어가 score : 0.0 으로 나오게 됨
  • 스코어를 계산하지 않기 때문에 keyword 값을 검색할 때는 filter 구문 안에 넣도록 함

filter 안에 넣은 검색 조건들은 스코어를 계산하지 않지만 캐싱이 되기 때문에 쿼리가 더 가볍고 빠르게 실행됨

keyword 뒤에 설명할 range 쿼리와 같이 스코어 계산이 필요하지 않은 쿼리들은 모두 filter 안에 넣어서 실행하는 것이 좋음

  • filter 쿼리 내에 여러 조건을 추가하고 싶을 때
```
[GET] summary/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term" : {"name": "rlatkd" }},
        { "terms" : {"category": ["a", "b"] }},
        { "range": { "createdAt": {"gte": "2024-06-12", "lte": "2024-06-13"}}}
      ]
    }
  }
}
```

filter 쿼리 내에 term, terms, range 는 relevance score를 계산하지 않기 때문에 캐싱이 됨

range

  • range 쿼리는 범위를 지정하여 범위에 해당하는 값을 갖는 document를 조회함
  • Filter Context이며, 정수, 날짜를 비교할 수 있음
  • range 쿼리에서 범위를 지정하는 파라미터
    • gte: 크거나 같음
    • gt: 큼
    • lte: 작거나 같음
    • lt: 작음
    • boost: 쿼리의 boost 값을 셋팅함 (기본값 1.0)
      • boost란 검색에 가중치를 부여함
  • 잔액이 20000 ~ 30000인 범위에 속하는 document를 조회
    {
      "query": {
        "bool": {
          "must": { "match_all": {} },
          "filter": {
            "range": {
              "balance": {
                "gte": 20000,
                "lte": 30000
              }
            }
          }
        }
      }
    }
  • 날짜도 숫자와 마찬가지로 range 쿼리 사용이 가능함
    {
      "query": {
        "bool": {
          "must": { "match_all": {} },
          "filter": {
            "range": {
              "date": {
                "gt": "2023-01-01"
              }
            }
          }
        }
      }
    }

term ( Term Level Queries )

  • term 쿼리는 역색인에 명시된 토큰 중 정확한 키워드가 포함된 document를 조회함
  • term 쿼리를 사용할 때 document가 조회되지 않는 이슈가 있을 수 있음
  • string 필드는 text타입 또는 keyword 타입을 갖음
  • text타입은 analyzer를 통해 역색인이 되는 반면, keyword 타입은 들어온 값 그대로 역색인이 됨
  • full text search를 하고자 할때에는 match쿼리를 사용하는 것이 좋음
    "query": {
        "term": {
          "address": "rlatkd"
        }
    }

terms

  • terms 쿼리는 배열에 나열된 키워드 중 하나와 일치하는 document를 조회함
  • address 필드에 rlatkd, banana, apple 키워드가 하나라도 존재하는 document를 조회
    {
      "query": {
        "terms": {
          "address": ["rlatkd", "banana", "apple"]
        }
      }
    }

regexp

  • regexp 쿼리는 정규 표현식 term 쿼리를 사용할 수 있음
  • regexp 쿼리는 Term Level 쿼리(정확한 검색)임
  • address 필드에서 끝 문자열이 rlatkd인 document를 조회
    {
        "query": {
            "regexp":{
                "address": ".*rlatkd"
            }
        }
    }
  • 정규식 형식
    • - . : 모든 문자열
    • - * : 0개 이상의 자리수

검색 결과 가공

from, size

  • from과 size 필드는 pagination 개념과 관련이 있음
    • from: 쪽수
    • size: 한 번에 나타날 게시글 수
  • SQL
    • from: offset
    • size: limit

from은 default 0이고, size는 default 10임

  • 3개의 document만 반환하도록 조회
```
{
   "from" : 0,
   "size" : 3,
   "query":{
      "match_all":{}
   }
}
```

sort

  • sort 쿼리로 특정 필드마다 하나 이상의 정렬을 추가 할 수 있음
  • sort 쿼리를 사용하지 않을 경우, 기본 정렬은 _score 내림차순(desc)이며, 다른 항목으로 정렬할 경우 오름차순(asc)으로 기본 설정됨
  • age 필드에 대해 내림차순으로 정렬한 후, fruits 필드에 대해 내림차순으로 정렬하고 address를 내림차순으로 정렬
    {
       "sort" : [
            { "age" : "desc" },
            { "fruits" : "desc" },
            "_address"
        ],
       "query":{
          "match_all":{}
       }
    }

source filtering

  • source 필드를 통해 검색된 데이터에서 특징 필드들만 반환하도록 할 수 있음
  • SQL에서 SELECT 쿼리를 날릴 때 특정 컬럼들을 명시하는 것과 유사
  • 검색된 document들에 대해 모든 필드들을 응답받지 않는 조회
    {
       "_source": false,
       "query":{
          "match_all":{}
       }
    }
  • 검색된 document들에 대해 address, fruits 필드만 응답받는 조회
    {
       "_source": ["address","fruits"],
       "query":{
          "match_all":{}
       }
    }

0개의 댓글