본문 바로가기

Elasticsearch

[Elasticsearch] bool 복합 query 개념 정리 및 예제

반응형

 

Elasticsearch bool 복합쿼리 개념 정리 및 실습 / 예제 

elasticsearch 검색에 있어 정확한 검색을 위해 bool 쿼리는 기본적으로 쓰이는 아주 유용한 query이다. 그동안 기존 코드를 사용하고 대강만 알고 있었는데 elasticsearch guide book 을 통해 정확하게 공부하고 정리해 보았다. match_all, match, match_phrase을 구별할 줄 안다면 Bool query는 금방 습득할 수 있다.  

 

여러 조건을 모두 통합해서 검색을 할 때 상위에 Bool query를 사용한다. bool query는 다음과 같은 4개의 인자를 가지고 있다. 

 

Bool Query
must 반드시 해당 쿼리가 도큐먼트에 존재해야 검색됨
must_not 쿼리가 거짓인 도큐먼트들을 검색
should "must"처럼 반드시까진 아니고 옵셔널한 느낌 - should 쿼리 내용이 있으면 더 높은 점수를 받는다. (없어도 되지만 있으면 좋은..)
검색 결과  이 쿼리에 해당하는 도큐먼트의 score 점수를 높인다.
filter 쿼리가 참인 도큐먼트를 필터한다. 하지만 score계산에 영향을 주지 않는다. 
must보다 검색 속도가 빠르고 캐싱이 가능하다.

 

 

실습하기 전, index 하나 만들고 bulk로 데이터들을 넣어놓기 

PUT test_index

POST test_index/_bulk
{"index": {"_id":1}}
{"message": "The little cute cat" }
{"index": {"_id":2}}
{"message": "The little cute cat eats the red fish" }
{"index": {"_id":3}}
{"message": "The little cute cat eats the brown fish" }
{"index": {"_id":4}}
{"message": "The cute cat little fish" }
{"index": {"_id":5}}
{"message": "the red fish" }

 

 

1. bool - must 로 매칭되는 데이터 검색하기 

GET test_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": "cat"
          }
        },
        {
          "match_phrase": {
            "message": "brown fish"
          }
        }
        ]
    }
  }
}

 

결과 : 

{
  "took" : 58,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.6690354,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.6690354,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      }
    ]
  }
}

=> "cat"과 "brown fish" 둘 다 매칭되는 도큐먼트 1개가 나왔다. 

 

 

 

 

2. bool - must_not 검색하기 

위의 코드 must를 -> must_not으로 수정만 하면 "cat"과 "brown fish" 둘 다 모두 가지고 있지 않은 도큐먼트가 나온다. 

GET test_index/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "message": "cat"
          }
        },
        {
          "match_phrase": {
            "message": "brown fish"
          }
        }
        ]
    }
  }
}

결과 : 

{
  "took" : 72,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.0,
        "_source" : {
          "message" : "the red fish"
        }
      }
    ]
  }
}

 

 

 

 

3. bool - should 사용하기 

should 쿼리는 매칭되는 데이터에 가중치를 부여한다. 

먼저 should 없이 매칭되는 쿼리를 날려보면, 

GET test_index/_search
{
  "query": {
    "match": {
      "message": "eats"
    }
  }
}

결과 : 

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.744874,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.744874,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.744874,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      }
    ]
  }
}

"eats"가 들어간 데이터 2건이 나온다. 

 

여기서 "brown"매칭되는 데이터에 should 가중치를 넣어보기 

GET test_index/_search
{
  "query": {
    "bool": {
      "must": [
          {
          "match": {
            "message": "eats"
          }
        }
      ],
      "should": [
        {
          "match": {
            "message": "brown"
          }
        }
      ]
    }
  }
}

결과 : 

  "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.924373,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.744874,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      }
    ]

eats만 매칭되는 건 0.7448~ 점수였는데 should 쿼리로 "brown"과 매칭되는 걸 찾으니 1.9로 점수가 확 뛰었다. must는 반드시 있어야 해 ! 이고 Should는 매칭되는걸 우선적으로 검색해서 데꼬오자 ! 근데 매칭안되는 건 냅둬~ 느낌 

 

should는 옵셔널하게 사용하고 반드시 포함되어야할 쿼리가 있다면 must를 사용하기! 

 

 

4. match 와 should의 콜라보 

match와 should의 콜라보는 우리와 친숙한 쿠팡, 에이블리 등등 플랫폼의 상품 검색 등 검색에서 좋은 결과를 가져다 준다. 예를 들어 아마존에서 고객이 "little fish"를 검색했을 때 "little red fish", "little fish", "red fish", "brown fish"... 등이 나올 것인데, 연관된 것 중 고객이 검색한 검색어와 정확히 일치하는 단어에 가중치를 두고 싶다면 아래와 같이 사용하면 된다. 

 

GET test_index/_search
{
  "query": {
    "bool": {
      "must": [
          {
          "match": {
            "message": "little fish"
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "message": "little fish"
          }
        }
      ]
    }
  }
}

match 에서 "little" 또는 "fish"  (or operator) 둘 중 하나만 일치해도 모든 검색어를 가져오고 그 다음 should에서 match_phrase로 정확한 "little fish" 단어를 가진 데이터에 가중치를 주어 아래와 같은 결과가 나왔다 .

 

결과 : 

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 1.2034782,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.2034782,
        "_source" : {
          "message" : "The cute cat little fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.35513458,
        "_source" : {
          "message" : "the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.32575765,
        "_source" : {
          "message" : "The little cute cat"
        }
      }
    ]
  }
}

 

 

 

5. filter - 점수 score에 영향을 주지 않지만 빠르게 Yes or No 검색 가능

위에서 Bulk로 입력한 message 데이터 하나만으로는 filter 사용하기가 애매해서 다른 데이터를 더 넣고 실습해보기 

- filter는 보통 false / true 와 같은 모아니면 도 데이터 또는 Range 에 많이 쓰인다고 한다. 

 

아까 사용한 bulk 에 flag 값만 추가 

POST test_index/_bulk
{"index": {"_id":1}}
{"message": "The little cute cat", "flag": false }
{"index": {"_id":2}}
{"message": "The little cute cat eats the red fish", "flag": true }
{"index": {"_id":3}}
{"message": "The little cute cat eats the brown fish", "flag": true }
{"index": {"_id":4}}
{"message": "The cute cat little fish", "flag": false }
{"index": {"_id":5}}
{"message": "the red fish", "flag": true }

그대로 해도 _id가 적혀있어서 덮어 씌워진다. (결과를 보면 result: updated, version : 2 로 나온다) 

 

GET test_index/_search
{
  "query": {
    "bool": {
      "must": [
          {
          "match": {
            "message": "little fish"
          }
        }
      ],
      "filter": [
        {
          "match": {
            "flag": true
          }
        }
      ]
    }
  }
}

little 또는  fish 를 가진 데이터 중에 flag 필드가 True인 데이터 검색하기 

 

결과 : 

{
  "took" : 14,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.48953635,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the red fish",
          "flag" : true
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the brown fish",
          "flag" : true
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.35513458,
        "_source" : {
          "message" : "the red fish",
          "flag" : true
        }
      }
    ]
  }
}

filter는 score에 영향을 미치지 않는다.! 

 

filter 정리 끝,,,

 

 

 

 

match & match_all & match_phrase 사용법 및 차이에 대해 알아보기

 

[elasticsearch] match_all, match, match_phrase 사용 방법 및 차이점

match_all, match, match_phrase 사용 방법 및 차이점 실습 전, 준비사항 test_index에 먼저 bulk로 데이터 입력해주기 & kibana POST test_index/_bulk {"index": {"_id":1}} {"message": "The little cute cat" } {"index": {"_id":2}} {"messag

blckchainetc.tistory.com

 

Reference : https://esbook.kimjmin.net/05-search/5.2-bool

 

5.2 Bool 복합 쿼리 - Bool Query - Elastic 가이드북

표준 SQL의 AND, OR 조건 들은 2개의 조건값에 대한 이항 연산자 입니다. 하지만 Elasticsearch의 must, must_not, should 등은 내부에 있는 각각의 쿼리들에 대해 이 쿼리는 참 또는 거짓으로 적용하는 단항

esbook.kimjmin.net

반응형