ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ES - 데이터 검색
    🔍 elastic search 2022. 9. 21. 19:55

    ES는 검색에 사용하기 위한 데이터를 저장할 때 Term 으로 분석 과정을 거쳐 저장하기 때문에 검색 시,

    대소문자, 단수나 복수, 원형 여부와 상관없이 검색이 가능하다.

    • 이러한 특징을 Full Text Search ( = 전문 검색) 이라고 한다.

    Query DSL

    Elasticsearch는 검색을 위한 쿼리 기능을 제공

    • 이런 데이터 시스템에서 제공하는 쿼리 기능을 Query DSL(Domain Specific Language) 이라고 이야기 한다.
    • Elasticsearch의 Query DSL은 모두 JSON 형식으로 입력

    검색 API를 사용해 Elastic search 데이터 스트림 또는 인덱스에 저장된 데이터를 검색하고 집계할 수 있다.

    • API 쿼리 요청 본문 매개 변수는 Query DSL로 작성된 쿼리를 사용

    두 가지로 구분할 수 있다.

    1. 리프 쿼리 절
      • 리프 쿼리 절은 ‘match’, ‘term’ 또는 ‘range’ 쿼리와 같은 특정 필드에서 특정 값을 찾는다.
      • 이러한 쿼리는 스스로 사용 가능
    2. 복합 쿼리 절
      • 복합 쿼리 절은 다른 리프 또는 복합 쿼리를 감싸며 논리적인 방식으로 여러 쿼리를 결합하거나 동작을 변경하는데 사용

    관련성 점수

    ES는 검색을 했을 때 검색 결과에 대해서 일치하는 정도 를 측정하는 점수를 가지고, 해당 점수에 따라 검색 결과를 정렬

    관련성 점수 : 검색 API를 호출했을 때 _score 필드의 값

    • 점수가 높을 수록 문서의 관련성이 높다.
    • 각 쿼리 유형은 관련성 점수를 다르게 계산할 수 있다.
    • 점수 계산은 쿼리 절이 쿼리 컨텍스트에서 실행되는지, 필터 컨텍스트에서 실행되는지에 따라 달라진다.

    쿼리 컨텍스트 / 필터 컨텍스트

    쿼리 컨텍스트 (Query context)

    • 쿼리 절이 “쿼리와 문서와 얼마나 잘 일치 하는가?” 라는 질문에 답한다.
    • _score를 통해 문서가 다른 문서와 비교하여 쿼리와 얼마나 일치하는지를 계산

    필터 컨텍스트 (Filter context)

    • 쿼리 절이 “쿼리가 문서와 일치하는가?” 라는 질문에 답한다.
    • _score는 계산하지 않는다.
    • 대부분 필터링을 위해 사용

    정확한 검색이 아닌 유사검색( 문자 검색 )과 같은 것은 query context 를 사용하고 정확한 검색을 원할 때는 filter context 를 사용!

    실습


    index 세팅

    foods 인덱스에 name(이름, text), price(가격, integer), count(수량, integer), store(가게, keyword) 이 매핑

    PUT /foods
    {
      "mappings": {
        "properties": {
          "name": {
            "type": "text"
          }, 
          "price": {
            "type": "integer"
          }, 
          "count": {
            "type": "integer"
          }, 
          "store": {
            "type": "keyword"
          }
        }
      }
    }
    
    POST _bulk
    {"index":{"_index":"foods", "_type" : "_doc", "_id":"1"}}
    {"name":"음식1", "price": 1000, "count": 90, "store": "A"}
    {"index":{"_index":"foods", "_type" : "_doc", "_id":"2"}}
    {"name":"음식23", "price": 10000, "count": 90, "store": "A"}
    {"index":{"_index":"foods", "_type" : "_doc", "_id":"3"}}
    {"name":"음식3", "price": 15000, "count": 80, "store": "B"}
    {"index":{"_index":"foods", "_type" : "_doc",  "_id":"4"}}
    {"name":"음식4", "price": 16000, "count": 74, "store": "B"}
    {"index":{"_index":"foods", "_type" : "_doc", "_id":"5"}}
    {"name":"음식43", "price": 17000, "count": 50, "store": "A"}
    

     

    // 인덱스 만들기 curl 
    
    curl -XPUT 'localhost:9200/test_index' -H 'Content-type:application/json' -d  '{ "mappings": { "properties": {"text_name":{ "type": "text"},"keyword_name": {"type":"keyword"}}}}'

     

    // 인덱스 만들어졌는지 확인 
    
    curl -XGET 'localhost:9200/test_index/'
    

     

    // bulk api curl 
    
    curl -X POST "localhost:9200/foods/_bulk?pretty" -H 'Content-Type: application/json' -d'
    { "index" : { "_index" : "test", "_id" : "1" } }
    { "field1" : "value1" }
    { "delete" : { "_index" : "test", "_id" : "2" } }
    { "create" : { "_index" : "test", "_id" : "3" } }
    { "field1" : "value3" }
    { "update" : {"_id" : "1", "_index" : "test"} }
    { "doc" : {"field2" : "value2"} }
    '

    Full Text 쿼리

    • 분석된 텍스트 필드를 검색
    • 인덱싱 중에 필드에 적용된 분석기와 동일한 분석기를 사용하여 처리
    쿼리 설명
    match - 전체 텍스트 검색을 수행하기 위한 표준 쿼리

    - 주어진 텍스트는 검색하기 전 분석된다.

    - 띄워쓰기가 포함되서 값이 주어지는 경우 OR 로 조회한다.
    match_all 별다른 조건 없이 해당 인덱스의 모든 도큐먼트를 검색한다.
    match_phrase 입력된 검색어를 순서까지 고려해 검색을 수행한다.
    query_string - URL 검색에 사용하는 Lucene의 검색 문법을 본문 검색에 이용하고 싶을 때 사용한다.

    - 구문을 사용하여 AND 또는 NOT와 같은 연산자를 기반으로 제공된 쿼리 문자열을 구문 분석 및 분할한다.

    - 다음 쿼리는 일치하는 문서를 반환하기 전에 분할된 각 텍스트를 독립적으로 분석한다.

    1. match_all

    GET foods/_search
    {
      "query":{
        "match_all":{ }
      }
    }
    
    curl -XPOST 'localhost:9200/foods/_search?pretty' -H 'Content-Type: application/json' -d'{                       ✔ │ base 
      "query": {
          "match_all": {}
      }
    }'
    

     

    해당 인덱스에 있는 모든 데이터가 노출

     

    2. match

    • 공백이 OR 연산자로 작동한다.
    GET foods/_search
    {
      "query": {
        "match": {
          "name": "음식1"
        }
      }
    }
    
    curl -X GET "localhost:9200/foods/_search?pretty" -H 'Content-Type: application/json' -d'
    {
      "query": {
        "match": {
          "name": "음식1 음식3"
        }
      }
    }
    '
    // 음식1  OR 음식3 으로 검색된다.
    

    이를 AND로 바꾸고 싶다면 operator를 명시해 준다.

    curl -X GET "localhost:9200/foods/_search?pretty" -H 'Content-Type: application/json' -d'
    {
      "query": {
        "match": {
          "name": "음식1 음식3",
    			"operator": "and"
        }
      }
    }
    '
    

    3. match_phrase

     match 쿼리와 거의 동일하게 작동하지만 순서까지 필터링 한다.

     

    ex) my name 이라는 값이 있다면 my name 이라고 검색해야 값이 나온다

    • name my 으로 검색하는 경우는 값 ❌
    GET /_search
    {
      "query": {
        "match_phrase": {
          "name": "음식1 음식3"
        }
      }
    }
    
    curl -X GET "localhost:9200/foods/_search?pretty" -H 'Content-Type: application/json' -d'
    {
      "query": {
        "match_phrase": {
          "name": "음식1 음식3"
        }
      }
    }
    '
    

    4. query_string

    GET /_search
    {
      "query": {
        "query_string": {
          "query": "(new york city) OR (big apple)",
          "default_field": "content"
        }
      }
    }
    
    curl -X GET "localhost:9200/foods/_search?pretty" -H 'Content-Type: application/json' -d'
    {
      "query": {
        "query_string": {
          "query": "음식1 OR 음식3",
          "default_field": "name"
        }
      }
    }
    '
    

     

    내장된 쿼리 분석기를 이용하는 질의 작성 가능

    bool 복합 쿼리

    • Lucene BooleanQuery 에 매핑
    • 여러 쿼리를 조합하기 위해서는 상위에 bool 쿼리를 사용하고 그 안에 다른 쿼리들을 넣어 사용

    1. must

    POST _search
    {
      "query": {
        "bool" : {
          "must" : {
            "match" : { "name" : "음식1" }
          }
        }
      }
    }

    2. filter

    POST _search
    {
      "query": {
        "bool" : {
          "filter": {
            "match" : { "name" : "음식1" }
          }
        }
      }
    }

    3. should

    POST _search
    {
      "query": {
        "bool" :  {
          "should" : [
            { "match" : { "name" : "음식1" },
            { "match" : { "name" : "음식3" } }
         ]
        }
      }
    }
    • should를 단독으로 사용할 때 
      • OR로 적용이 된다.
    POST _search
    {
      "query": {
        "bool" :  {
          "should" : [
            { "match" : { "name" : "음식1" },
            { "match" : { "name" : "음식3" } }
         ],
    			"must" : [
    			{
    				"match" : {
    						"store"  : "A"
    				}	
    			]
        }
      }
    }
    • 다른 쿼리와 복합적으로 사용하는 경우 - score로 적용
      • 다른 쿼리에 속한 값이 노출
      • should에 있는 조건인 경우 더 높은 score를 부여한다.

    Term-level 쿼리

    • Analyer를 사용하지 않고 정확한 값을 조회하는 쿼리
    • 검색어를 분석하지 않는다.
    • keyword 타입을 대상으로 한다.
    쿼리 설명
    exists 실제 값이 존재하는 문서만 반환
    fuzzy Levenshtein 편집 거리로 측정한 검색어와 유사한 용어를 포함하는 문서를 반환
    range 범위 내 데이터를 리턴하는 쿼리
    term 제공된 필드에 정확한 용어가 포함된 문서를 반환
    terms 제공된 필드에 하나 이상의 정확한 용어가 포함된 문서를 반환
    wildcard 와일드카드 패턴과 일치하는 용어를 포함하는 문서를 반환
    1. exist
      • score 에 값이 있는 도큐먼트만 노출
      GET /_search
      {
        "query": {
          "exists": {
            "field": "store"
          }
        }
      }
      
    2. term
      • 별도의 분석 작업 수행 하지않고 입력된 텍스트가 존재하는 문서를 찾는다.
      GET /_search
      {
        "query": {
          "term": {
            "name": {
              "value": "음식1"
            }
          }
        }
      }
      
    3. terms
      • term과 동일하게 작동하지만, 여러개의 검색어를 한번에 찾을 수 있다.
      GET /_search
      {
        "query": {
          "terms": {
            "name": [ "음식1", "음식2" ],
          }
        }
      }
      
    4. wildcard
      • 검색어가 와일드카드와 일치하는 구문을 찾고, 입력된 검색어는 형태소 분석이 이루어지지 않는다.
      GET /_search
      {
        "query": {
          "wildcard": {
            "name": {
              "value": "음*1"
            }
          }
        }
      }
      
      음…….1 인 document를 찾는다.

    참고자료

    https://esbook.kimjmin.net/05-search

    https://velog.io/@soyeon207/ES-5.-데이터-검색하기

    '🔍 elastic search' 카테고리의 다른 글

    ES - Aggregations  (0) 2022.09.22
    ES - 텍스트 분석  (0) 2022.09.22
    ES - 기본 API  (0) 2022.09.21
    Docker로 ES 설치하기  (1) 2022.09.21
    ElasticSearch  (0) 2022.09.20

    댓글

Designed by Tistory.