Blog

2016.05.31 - 번역 - Lost in Translation: Boolean Operations and Filters in the Bool Query ...

drscg 2019. 1. 7. 08:56

With 5.0 on the horizon, a number of query types deprecated in 2.x will be removed. Many of those are replaced by functionality of the bool query, so here’s a quick guide on how to move away from filtered queriesandornot queries; and a general look into how to parse boolean logic with the bool query.

5.0 이 출시되면서, 2.x 에서 deprecate된 많은 query 유형이 제거된다. 그들 중 많은 부분이 bool query 기능으로 대체된다. 그래서, 여기에서 filtered queriesandornot query를 대체하는 방법과 bool query로 구성된 boolean login을 분석하는 일반적인 방법에 대한 가이드를 제공한다. 

For the examples used in this article, let's assume this scenario: A school surveyed its students on their preferences for fruit snacks. Now you're putting together an application so administrators can view this data. Because of the many grades, categories, and other features of the data, you may find you have some arbitrarily complex boolean logic to deal with.

이 게시물에 사용된 예를 위해, 다음과 같은 시나리오를 가정해 보자. 어떤 학교에서 학생들의 과일 스낵의 선호도를 조사하였다. 이제 관리자가 이 data를 볼 수 있도록 application을 통합한다. 많은 학년, 범주, 기타 data의 형태 때문에, 임의의 복잡한 boolean logic을 처리할 수 있어야 한다.

Matching Boolean Operations with the Bool Query Fields

Let's get to the heart of these boolean operations and how they'd look without the and, or, not queries. In the bool query, we have the following fields:

boolean 연산의 핵심과 and, or, not query 없이 그들을 보는 방법을 알아보자. bool query에는 다음과 같은 field가 있다.

  • must
  • must_not
  • should
  • filter

Must is analogous to the boolean ANDmust_not is analogous to the boolean NOT, and should is roughly equivalent to the boolean OR. Note that should isn't exactly like a boolean OR, but we can use it to that effect. And we’ll take a look at filter later on.

must 는 AND 와 유사하고, must_not 은 NOT 과 유사하고, should 는 OR 와 거의 같다. should 는 OR 와 정확히 같지는 않지만, 그 효과에 사용할 수 있다. 나중에 filter 를 살펴보겠다.

Boolean AND and NOT are easy, so let's look at those two first. If you want documents where preference_1 = Apples AND preference_2 = Bananas the bool query looks like this:

AND 와 NOT 은 쉬우니, 이 둘을 먼저 살펴보자. preference_1 = Apples AND preference_2 = Bananas 인 document를 원한다면, bool query는 다음과 같다.

{
  "query" : {
    "bool" : {
      "must": [{
        "match": {
          "preference_1": "Apples"
        }
      }, {
        "match": {
          "preference_2": "Bananas"
        }
      }]
    }
  }
}

If you want documents where preference_1 != Apples:

preference_1 != Apples 인 document를 원한다면

{
  "query" : {
    "bool" : {
      "must_not": {
        "match": {
          "preference_1": "Apples"
        }
      }
    }
  }
}

But what about OR? That's where the should parameter comes in. If you want the set of documents where preference_1 = Apples OR preference_1 = Raspberries:

그렇다면 OP는 어떨까? 여기에서 should 가 필요하다. preference_1 = Apples OR preference_1 = Raspberries 인 document를 원한다면

{
  "query" : {
    "bool" : {
      "should": [{
        "match": {
          "preference_1": "Apples"
        }
      }, {
        "match": {
          "preference_1": "Raspberries"
        }
      }]
    }
  }
}

So these, then, can all be combined into much more complex boolean logic, because we can easily nest bool queries. So let's look at this boolean logic: (preference_1 = Apples AND preference_2=Bananas) OR (preference_1 = Apples AND preference_2 = Cherries) OR preference_1 = Grapefruits

따라서, 이들은 훨씬 더 복잡한 bool query로 조합될 수 있다. 왜냐하면 쉽게 bool query를 내장(nest)할 수 있기 때문이다. 다음 boolean logic을 살펴보자. (preference_1 = Apples AND preference_2=Bananas) OR (preference_1 = Apples AND preference_2 = Cherries) OR preference_1 = Grapefruits

So in this case, you are searching for documents that match this set of rules, so documents where preference_1 is Apples and term 2 is either Bananas or Cherries, OR preference_1 is grapefruit, regardless of what term 2 equals.

이 경우, 이 rule에 일치하는 document를 search하고 있으므로, preference_1 이 Apples 이고, 2번째 단어(preference_2)가 Bananas 또는 Cherries이거나(OR), 2번째 단어(preference_2)에 관계없이 preference_1 이 grapefruit인 document이다.

That logic translates into a query that looks like this:

이 logic을 query로 바꾸면 아래와 같다.

{
  "query": {
    "bool": {
      "should": [{
        "bool": {
          "must": [{
            "match": {
              "preference_1": "Apples"
            }
          }, {
            "match": {
              "preference_2": "Bananas"
            }
          }]
        }
      }, {
        "bool": {
          "must": [{
            "match": {
              "preference_1": "Apples"
            }
          }, {
            "match": {
              "preference_2": "Cherries"
            }
          }]
        }
      }, {
        "match": {
          "preference_1": "Grapefruit"
        }
      }]
    }
  }
}

To break this down a bit further:

이를 좀 더 자세히 설명하면 다음과 같다.

Note that the whole of this query is wrapped in a should which satisfies the three OR clauses, and each individual piece is its own nested bool query.

이 query 전체는 3개의 OR 절을 만족하는 should 로 둘러싸여 있으며, 각 개별 절은 자체에 내장된(nested) bool query이다.

So the (preference_1 = Apples AND preference_2=Bananas) piece is

따라서, (preference_1 = Apples AND preference_2=Bananas) 절은

{
  "bool": {
    "must": [{
      "match": {
        "preference_1": "Apples"
      }
    }, {
      "match": {
        "preference_2": "Bananas"
      }
    }]
  }
}

And because this is all wrapped in a should, the next in the chain would be an OR

그리고, 이것은 should로 둘로싸여 있으므로, OR로 묶일 것이다.

So the preference_1 = Apples AND preference_2 = Cherries piece would be another bool:

preference_1 = Apples AND preference_2 = Cherries 절은 또 다른 bool이 된다.

{
  "bool": {
    "must": [{
      "match": {
        "preference_1": "Apples"
      }
    }, {
      "match": {
        "preference_2": "Cherries"
      }
    }]
  }
}

And then finally the single term:

그리고 그 다음 마지막 단일 조건은

{
  "match": {
    "preference_1": "Grapefruits"
  }
}

The query can be arbitrarily complex, to fit your particular boolean requirement. Each piece can be broken down and turned into its elementary boolean expressions, then chained together as shown above, to make sure you're retrieving the right documents. It’s also worth noting here that you can set minimum_should_match to a value you choose. This is the prime difference of the should function from the boolean OR. By default , minimum_should_match defaults to 1, but if you would like for more than one should clause to match for a document to be returned, you can increase this value.

query는 특정 boolean 조건에 맞도록, 임의로 복잡하게 할 수 있다. 각 절은 분해되어 기본적인 boolean 표현으로 변환한 다음, 위에서 언급한 것처럼 함께 묶어, 올바른 document를 검색할 수 있다. 여기에서 minimum_should_match 을 원하는 값으로 설정할 수 있다는 점도 주목하자. 이것이 should 기능과 boolean OR 의 주요한 차이점이다. 기본적으로, minimum_should_match 의 기본값은 1이나, return할 document가 2개 이상의 should 절이 일치하도록 하려면, 이 값을 증가할 수 있다.  

Filtered Queries

Because filtered queries have also been deprecated in 2.x, the new method is the filter field in the bool query. So let's take our boolean logic from before: (preference_1 = Apples AND preference_2=Bananas) OR (preference_1 = Apples AND preference_2 = Cherries) OR preference_1 = Grapefruits.

filtered query는 2.x에서 deprecate되어, bool query에 새로운 method filter field를 추가했다. 자, 이전의 boolean logic을 살펴보자. (preference_1 = Apples AND preference_2=Bananas) OR (preference_1 = Apples AND preference_2 = Cherries) OR preference_1 = Grapefruits.

Let’s say an administrator is focusing on grade 2, so they want to see only the results for that grade. It would just be a matter of adding a filter to the bool to get only those documents. If you are filtering documents, keep in mind that the relevance score for the returned results is only affected by the query, not by the filter, so it’s possible that your relevance scoring may not be what you expect, since it’s the query that sets the score, not the filter.

관리자가 2학년에 집중한다고 가정해 보면, 해당 학년의 결과만 보려할 것이다. bool에 filter 를 추가하여, 해당 document만 가져올 수 있다. document를 filtering할 경우, return된 결과의 relevance score는 filter가 아닌 query의 영향만을 받는다는 것을 기억하자. 따라서, relevance score가 예상과 다를 수 있다. score를 계산하는 것은 filter가 아니라 query이기 때문이다.

Here’s what the filter looks like:

filter의 예는 다음과 같다.

"filter" : {
  "term": {
    "grade": "2"
  }
}

So the whole query looks like this:

따라서, 전체 query는 다음과 같다.

{
  "query": {
    "bool": {
      "should": [{
        "bool": {
          "must": [{
            "match": {
              "preference_1": "Apples"
            }
          }, {
            "match": {
              "preference_2": "Bananas"
            }
          }]
        }
      }, {
        "bool": {
          "must": [{
            "match": {
              "preference_1": "Apples"
            }
          }, {
            "match": {
              "preference_2": "Cherries"
            }
          }]          
        }
      }, {
        "match": {
          "preference_1": "Grapefruit"
        }
      }],
      "filter" : {
        "term": {
         "grade": "2"
        }
      }
    }
  }
}

As you can see, the bool query is quite versatile, but sometimes parsing out the complex boolean operations into the bool query syntax can be a challenge. Hopefully, this has given you a better idea of how each of the bool query fields map to traditional boolean operators, and how you can chain those together for complex boolean logic for better search results.

보다시피, bool query는 매우 다양한 기능을 가지고 있지만, 때로는 복잡한 boolean 연산을 bool query 문법으로 바꾸는 것은 어려울 수 있다. 이 게시물이 각각의 bool query field를 전통적인 boolean 연산에 매핑하는 방법과 복잡한 boolean logic을 위해 그들을 함께 묶는 방법을 이해하는데 도움이 되기 바란다.

Also, this hopefully has given you some ideas as you work to remove filtered and and, or, not queries using the bool query to make sure you are ready for 5.0 when it is released. As ever, please make sure you review all breaking changes and thoroughly test against your specific use case prior to upgrading.

또한, bool query를 사용하도록 filtered, and, or, not query를 제거하거나 release될 5.0 위한 준비작업을 하는데 약간이라도 도움이 되기 바란다. 이전처럼, 모든 breaking changes을 검토하고 upgrade 전에 철처히 테스트하기 바란다.

원문 : Lost in Translation: Boolean Operations and Filters in the Bool Query