Elk Stack/Elasticsearch

[Elasticsearch] Query Dsl

freedommmm 2021. 11. 4. 07:35

안녕하세요. 오늘은 Query Dsl에서 가장 중요하다고 생각하는 Query에 대한 기본적인 이론에 대해서 알아보도록 하겠습니다. 해당 부분을 본 후에는 Elasticsearch 검색 쿼리를 작성할 때 매핑된 타입 값에 따라서 해당 부분을 참고하면 좋을 것 같습니다.

 

Query는 크게 세가지로 나눠질 수 있습니다.

1. Query Context

- 정의

: Full text search를 의미하며, 검색어가 문서의 얼마나 매칭 되는지를 표현하여 hit score라는 값을 가진다. ex) 도서관에서 책의 내용을 바탕으로 가장 비슷한 책을 검색할 때 사용할 수 있습니다.

- 쿼리(중요하다고 생각하는 부분만 예시 쿼리를 써놨습니다.)

  1. match : 검색어로 들어온 문자열을 analyzer로 분석 후 해당 토큰들을 inverted index에서 문서를 검색할 수 있다.
    • analyzer을 바탕으로 Hello Elasticsearch는 토큰들로 분리됩니다. 그래서 inverted index에서 hello가 있는 doc과 elasticsearch가 있는 doc의 id값을 각각 수집하여 통합하여 클라이언트 노드로 결괏값을 보냅니다.
    • {
        "query": {
          "match":{
          	"검색필드1":"Hello Elasticsearch"
          }
        }
      }
  2. match_phrase : 나눠진 토큰들의 순서로 고려해서 search 한다. 그래서 검색하고자 하는 문자열의 전체 토큰을 가진 문서만 검색된다. 
    • analyzer을 바탕으로 Hello Elasticsearch는 토큰들로 분리됩니다. 그래서 inverted index에서 hello와 elasticsearch가 함께 있는 doc의 id값을 수집하여 클라이언트 노드로 결과값을 보냅니다.
    • {
      	"query":{
          		"match_phrase":{
              		"검색 필드값": "Hello Elasticsearch"
              	}
          	}
      }
  3. multi_match : 두 개 이상의 필드에 match 쿼리를 날릴 수 있습니다.
    • match와 동일하지만 두 개 이상의 필드에 match 쿼리 날릴 수 있습니다.
    • {
      	"query":{
          		"multi_match":{
              		"query": "Helo Elasticsearch",
                      	"fields" : [검색 필드값1, 검색 필드값2]
              	}
          	}
      }
  4. query_string : match와 multi_match처럼 동일하게 동작할 수 있으며, and와 or 쿼리로 동작할 수 있습니다. 하지만 wildcard를 붙이는 부분은 비효율 적일 수 있으므로 되도록이면, match를 쓰거나 다른 쿼리를 쓰도록 하자.
    • {
      	"query":{
          		"query_string":{
              		"fields": ["title"],
                      	"query":"*nux"
              	}
          	}
      }

2. Filter Context(Term Level Query)

- 정의

: 검색어가 문서에 존재하는지 여부를 yes나 no 형태의 검색결과로 보여준다. 쉽게 말해, 검색어에 해당 토큰의 포함 여부를 찾는 형태이다. score 값을 가지지 않는다. 도서관에서 정확한 책의 제목을 바탕으로 책의 유무를 검색할 때 사용합니다. 또한, analyzer 과정을 거치지 않아서 대소문자 구분 및 빠르게 동작할 수 있습니다.

- 쿼리(중요하다고 생각하는 부분만 예시 쿼리를 써놨습니다.)

  1. term : 검색어로 입력한 단어와 정확하게 일치하는 단어가 있는 문서를 찾는다.
    • inverted index에 analyzer 하지 않은 검색어로 검색하기 때문에 색인된 데이터는 analyzer 된 데이터이므로 정확하게 일치하는 것을 찾아야 한다.
    • {
      	"query":{
          		"term":{
              		"검색 필드값": "Hello Elasticsearch"
              	}
          	}
      }
  2. terms : 둘 이상의 term 쿼리를 사용할 때 사용하는 쿼리이다.
  3. range : 범위를 지정하여 특정 값의 범위 이내에 있는 경우를 검색할 때 사용합니다.
    • {
      	"query":{
          		"range":{
              		"date":{
                      		"gte": "2021/11/1",
                          		"lte": "2021/12/1"
                      	}
              	}
          	}
      }
  4. wildcard : 와일드카드 특수문자를 이용한 Full Scan 검색을 하는 방법이다. 하지만 wildcard query는 모든 inverted index를 하나하나 확인하기 때문에 검색 속도가 매우 느립니다. 그래서 keyword 타입에서 사용하며 match를 사용할 수 있으면 match 쿼리를 사용하는 편이 빠르다.
    • {
      	"query":{
          		"wildcard":{
              		"검색 필드값": "Hello*"
              	}
          	}
      }

3. Bool query

- 정의

: Query Context와 Filter Context를 조합해서 사용할 수 있는 방법입니다. 주의할 점은 위에서 query context와 filter context의 차이를 살펴봤습니다. 스코어링이 필요한 구문은 must와 should에 넣는 것이, 스코어링이 필요하지 않은 filter context는 filter절에 넣는 것이 조금 더 효과적으로 쿼리를 날릴 수 있습니다.

- 예시

{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "검색필드": "검색값"
          }
        },
        {
          "term": {
            "검색필드2": "검색값2"
          }
        }
      ],
      "must": [
        {
          "match": {
            "검색필드3": "검색값3"
          }
        }
      ]
    }
  }
}

- 쿼리

1. must : 항목 내 쿼리에 일치하는 문서를 검색합니다.

2. filter : 항목 내 쿼리에 일치하는 문서를 검색합니다.

3. should : 항목 내 쿼리에 일치하는 문서를 검색합니다.

4. must_not : 항목 내 쿼리에 일치하는 문서를 검색합니다.