GW LABS

기초부터 다지는 ElasticSearch 운영 노하우 (7) - 검색 엔진으로 활용하기 본문

Book-Review/Programing

기초부터 다지는 ElasticSearch 운영 노하우 (7) - 검색 엔진으로 활용하기

GeonWoo Kim 2022. 8. 30. 14:47

9.1 inverted index란

  • token: 공백 기준으로 문장을 나누어 생긴 단어
  • inverted index: 문서에서 토큰이 몇 번 출현했는지 빈도를 저장한 해시맵 형태의 자료구조
    • 검색 결과를 얻기 위해서는 토큰이 검색어와 정확하게 일치해야한다.
  • analyze API
    • 문자열이 어떻게 토크나이징 되는지 확인할 수 있는 API
curl --location --request GET 'localhost:9200/_analyze?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "analyzer": "standard",
    "text": "I am a boy"
}'

# 결과
{
    "tokens": [
        {
            "token": "i",
            "start_offset": 0,
            "end_offset": 1,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "am",
            "start_offset": 2,
            "end_offset": 4,
            "type": "<ALPHANUM>",
            "position": 1
        },
        {
            "token": "a",
            "start_offset": 5,
            "end_offset": 6,
            "type": "<ALPHANUM>",
            "position": 2
        },
        {
            "token": "boy",
            "start_offset": 7,
            "end_offset": 10,
            "type": "<ALPHANUM>",
            "position": 3
        }
    ]
}

 

9.2 analyzer 살펴보기

  • character filter, tokenizer, token filter로 구성
  • character filter
    • 문자열 전처리 과정수행 (특수문자 제거, HTML 태그 제거 등)
  • tokenizer
    • 일정한 기준(공백이나 쉼표 등)에 의해 문자열을 n개의 토큰으로 나눔
  • token filter
    • 토큰을 전부 소문자로 바꾸는 등 추가 처리를 token에 수행

 

9.3 analyzer와 검색의 관계

  • inverted index에서 token을 통해 검색하기 때문에, 비즈니스 니즈에 맞는 analyzer 채택 필요
  • 기존 인덱스에 설정한 analyzer를 바꾸고 싶을 때는 인덱스를 새로 만들어서 재색인(reindex) 해야 함

 

9.4 Search API

  • URI Search와 RequestBody 작성을 통한 API를 제공
# URI Search
curl --location --request GET 'localhost:9200/test_data/_search?q=title:elasticsearch&pretty'

# RequestBody
curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "term" : {"title" : "elasticsearch"}
    }
}'
  • requestBody 옵션
    • query: 실제 검색을 위한 쿼리문
    • from/size: 검색 결과를 n개의 단위로 나눠서 볼 때 사용
    • sort: 검색 결과를 _score가 아닌 별도의 필드를 기준으로 정렬
    • source: 검색 결과 중 특정 필드의 내용만을 보고자 할 때 사용
    • highlighting: 검색 결과 중 검색어와 매칭하는 부분을 강조하기 위해 사용
    • boost: 검색 결과로 나온 스코어를 변경할 때 사용
    • scroll: 검색 결과를 n개의 단위로 나눠서 볼 때 사용. from/size와 유사하지만 scroll id를 통해서 다음번 결과를 가져올 수 있음

 

9.5 Query DSL이란

  • Query context: Full text search를 의미하며, 검색어가 문서와 얼마나 매칭되는지를 표현하는 score라는 값을 가진다.
  • Filter context: 검색어가 문서에 존재하는지 여부를 Yes나 No 형태의 검색 결과로 보여준다. score값을 가지지 않음

 

9.6 Query Context

  • match: 검색어가 토크나이징된 토큰들이 존재하는지 여부를 확인한다.
  • match_phrase: match와 비슷하지만 검색어에 입력된 순서를 지켜야 한다.
  • multi_match: match와 동작 원리는 같으며 다수의 필드에 검색하기 위해 사용
  • query_string: and 와 or 같이 검색어 간 연산이 필요할 때 사용

 

9.6.1 match 쿼리

curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "match" : {
            "description" : "nginx guide"
        }
    }
}'

 

9.6.2 match_phrase 쿼리

curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "match_phrase" : {
            "description" : "Linux Kernel"
        }
    }
}'

 

9.6.3 multi_match 쿼리

curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "multi_match" : {
            "query" : "Kernel", 
            "fields": ["title", "description"]
        }
    }
}'

 

9.6.4 query_string 쿼리

curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "query_string" : {
            "query" : "*nux", 
            "fields": ["title", "description"]
        }
    }
}'

 

 

9.7 Filter Context

  • Term Level Query라고도 부르며 문서 필터링에 사용되는 쿼리이다.
  • term: 검색어로 입력한 던어와 정확하게 일치하는 단어가 있는지를 찾는다.
  • terms: term과 유사하지만 여러 개의 단어를 기준으로 하나 이상 일치하는 단어가 있는지 찾는다.
  • range: 특정 범위 안에 있는 값이 있는지 찾는다.
  • wildcard: 와일드카드 패턴에 해당하는 값이 있는지 찾는다.

 

9.7.1 term 쿼리

  • 토큰을 대상으로 검색을 하기 때문에 analyzer의 동작방식을 알고 검색을 수행해야한다. standard analyzer는 소문자로 모두 바꾸기 때문에 대문자로 검색하면 아무 검색결과도 얻을 수 없음
curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query" : {
        "term" : {
            "title" : "linux"
        }
    }
}'

 

9.7.3 range 쿼리

curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query" : {
        "range" : {
            "release_date" : {
                "gte" : "2015/01/01",
                "lte" : "2015/12/31"
            }
        }
    }
}'

 

 

9.8 bool query를 이용해 쿼리 조합하기

  • must에는 query context를, filter에는 filter context를 적용하는 것이 성능에서 유리하다.
  • must: 항목 내 쿼리에 일치하는 문서를 검색 (스코어링: O, 캐싱: X)
  • filter: 항목 내 쿼리에 일치하는 문서를 검색 (스코어링: X, 캐싱: O)
  • should: 항목 내 쿼리에 일치하는 문서를 검색 (스코어링: O, 캐싱: X)
  • must_not: 항복 내 쿼리에 일치하지 않는 문서를 검색 (스코어링: X. 캐싱: O)
curl --location --request GET 'localhost:9200/test_data/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "title": "nginx"
                    }
                }
            ],
            "filter": [
                {
                    "range" : {
                        "release_date": {
                            "gte": "2016/01/01",
                            "lte": "2017/12/31"
                        }
                    }
                }
            ]
        }
    }
}'

 

 

 

Comments