2.X/2. Search in Depth

2-1-3. Finding Multiple Exact Values

drscg 2017. 9. 30. 02:23

The term query is useful for finding a single value, but often you’ll want to search for multiple values.What if you want to find documents that have a price of $20 or $30?

term query는 단일 값을 찾는데 유용하다. 그러나, 가끔은 다중 값을 찾을 수도 있다. 가격이 $20 또는 $30인 document를 찾으려면 어떻게 해야 할까?

Rather than using multiple term queries, you can instead use a single terms query (note the s at the end). The terms query is simply the plural version of the singular term query cousin.

다수의 term query를 사용하기 보다는, 대신 하나의 terms(마지막에 s 가 있다.) query를 사용할 수 있다.terms query는 단수형인 term query의 단순한 복수형이다.

It looks nearly identical to a vanilla term too. Instead of specifying a single price, we are now specifying an array of values:

이것은 평범한 term 과 거의 동일하다. 하나의 가격을 지정하는 대신, 값의 배열을 지정한다.

{
    "terms" : {
        "price" : [20, 30]
    }
}

And like the term query, we will place it inside the filter clause of a constant score query to use it:

그리고, term query와 마찬가지로, 그것을 사용하기 위해 constant_score query의 filter 절 내부에 사용한다.

GET /my_store/products/_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "terms" : { 
                    "price" : [20, 30]
                }
            }
        }
    }
}

위에서 보듯이, terms query는 constant_score query 내부에 위치한다.

The query will return the second, third, and fourth documents:

query는 두 번째, 세 번째, 네 번째 document를 반환할 것이다.

"hits" : [
    {
        "_id" :    "2",
        "_score" : 1.0,
        "_source" : {
          "price" :     20,
          "productID" : "KDKE-B-9947-#kL5"
        }
    },
    {
        "_id" :    "3",
        "_score" : 1.0,
        "_source" : {
          "price" :     30,
          "productID" : "JODL-X-1937-#pV7"
        }
    },
    {
        "_id":     "4",
        "_score":  1.0,
        "_source": {
           "price":     30,
           "productID": "QQPX-R-3956-#aD8"
        }
     }
]

Contains, but Does Not Equaledit

It is important to understand that term and terms are contains operations, not equals. What does that mean?

term 과 terms 가 동일하다(equal) 가 아닌 포함하다(contain) 연산이라는 것을 이해하는 것은 중요하다.무슨 의미일까?

If you have a term query for { "term" : { "tags" : "search" } }, it will match both of the following documents:

{ "term" : { "tags" : "search" } } 이라는, term query가 있다고 하면, 아래의 두 document 모두 일치할 것이다.

{ "tags" : ["search"] }
{ "tags" : ["search", "open_source"] } 

search 라는 단어 외에 다른 단어도 가지고 있지만, 이 document는 반환된다.

Recall how the term query works: it checks the inverted index for all documents that contain a term, and then constructs a bitset. In our simple example, we have the following inverted index:

term query가 동작하는 방식을 기억해 보자. 어떤 단어를 포함하는, 모든 document를 inverted index에서 확인하고, bitset을 만든다. 예제에서 inverted index는 아래와 같다.

Token

DocIDs

open_source

2

search

1,2

When a term query is executed for the token search, it goes straight to the corresponding entry in the inverted index and extracts the associated doc IDs. As you can see, both document 1 and document 2 contain the token in the inverted index. Therefore, they are both returned as a result.

term query가 search 라는 token을 가지고 실행될 경우, inverted index의 해당하는 항목으로 바로 가서, 관련 있는 doc ID를 추출한다. 위에서 보있듯이, 두 document 1과 2는 inverted index에 그 token을 가지고 있다. 따라서, 결과로 두 document 모두를 반환한다.

Note

The nature of an inverted index also means that entire field equality is rather difficult to calculate. How would you determine whether a particular document contains onlyyour request term? You would have to find the term in the inverted index, extract the document IDs, and then scan every row in the inverted index, looking for those IDs to see whether a doc has any other terms.

inverted index의 본질은 또한, 전체 field를 공평하게(entire field equality) 계산하는 것이 어렵다는 것을 의미한다. 특정 document가 요청한 단어  을 포함하고 있다는 것을 판단하는 방법이 무엇일까? inverted index에서 단어를 찾고, document ID를 추출한다. 그 다음에, 해당 ID에 대해 document가 다른 단어를 가지고 있는가를 알아보기 위해, inverted index의 모든 행 을 스캔 해야 한다.

As you might imagine, that would be tremendously inefficient and expensive. For that reason, term and terms are must contain operations, not must equal exactly.

상상할 수 있겠지만, 그것은 굉장히 비효율적이고 비용이 많이 소요될 것이다. 그러한 이유로,term 과 terms 는 정확하게 동일하다(must equal exactly) 연산이 아닌, 반드시 포함하다(must contain) 연산이다.

Equals Exactlyedit

If you do want that behavior—entire field equality—the best way to accomplish it involves indexing a secondary field. In this field, you index the number of values that your field contains. Using our two previous documents, we now include a field that maintains the number of tags:

전체 field를 공평하게(entire field equality) 계산하기 위한, 가장 좋은 방법은, 보조 field의 색인을 포함하도록 하는 것이다. 이 field에, field가 포함하고 있는 값의 갯수를 색인하자. 이전의 두 document를 사용하여, 태그의 갯수를 관리하는 field를 포함하도록 하자.

{ "tags" : ["search"], "tag_count" : 1 }
{ "tags" : ["search", "open_source"], "tag_count" : 2 }

Once you have the count information indexed, you can construct a constant_score that enforces the appropriate number of terms:

갯수 정보가 색인되면, 적절한 단어의 수를 제한하는, constant_score 를 만들 수 있다.

GET /my_index/my_type/_search
{
    "query": {
        "constant_score" : {
            "filter" : {
                 "bool" : {
                    "must" : [
                        { "term" : { "tags" : "search" } }, 
                        { "term" : { "tag_count" : 1 } } 
                    ]
                }
            }
        }
    }
}

search 라는 단어를 가진 모든 document를 찾는다.

document가 하나의 tag만을 가지는지 확인한다.

This query will now match only the document that has a single tag that is search, rather than any document that contains search.

이제 이 query는 search 를 포함하는 document가 아닌, search 라는 하나의 tag를 가진 document만을 반환할 것이다.


'2.X > 2. Search in Depth' 카테고리의 다른 글

2-1-1. Finding Exact Values  (0) 2017.09.30
2-1-2. Combining Filters  (0) 2017.09.30
2-1-4. Ranges  (0) 2017.09.30
2-1-5. Dealing with Null Values  (0) 2017.09.30
2-1-6. All About Caching  (0) 2017.09.30