2.X/2. Search in Depth

2-1-5. Dealing with Null Values

drscg 2017. 9. 30. 02:14

Think back to our earlier example, where documents have a field named tags. This is a multivalue field. A document may have one tag, many tags, or potentially no tags at all. If a field has no values, how is it stored in an inverted index?

tags 라 이름 붙여진 field를 가진 document가 있는, 초기 예제를 다시 생각해 보자. 이 field는 다중 값 field이다. document는 하나의 태그 또는 다수의 태그를 가질 수도 있고, 어쩌면 전혀 없을 수도 있다. 만약 field가 아무런 값도 가지지 않는다면, inverted index에는 어떻게 저장될까?

That’s a trick question, because the answer is: it isn’t stored at all. Let’s look at that inverted index from the previous section:

묘한 질문이다. 답은 전혀 저장하지 않는다 이다. 이전의 inverted index를 살펴보자.

Token

DocIDs

open_source

2

search

1,2

How would you store a field that doesn’t exist in that data structure? You can’t! An inverted index is simply a list of tokens and the documents that contain them. If a field doesn’t exist, it doesn’t hold any tokens, which means it won’t be represented in an inverted index data structure.

해당 데이터 구조에 존재하지 않는 field를 어떻게 저장하겠는가? 할 수 없다. inverted index는 단순히 token과 token을 포함하고 있는 document의 목록이다. 만약 field가 존재하지 않는다면, 그것은 token을 가지고 있지 않다. 즉, inverted index 데이터 구조에서 그것을 표현할 수 없다는 의미이다.

Ultimately, this means that a null[] (an empty array), and [null] are all equivalent. They simply don’t exist in the inverted index!

결국, 이것은 null[](비어 있는 배열) 그리고 [null] 과 모두 동일하다는 것을 의미한다. 간단히 말해서, 그것들은 inverted index에 존재하지 않는다.

Obviously, the world is not simple, and data is often missing fields, or contains explicit nulls or empty arrays. To deal with these situations, Elasticsearch has a few tools to work with null or missing values.

알다시피, 이 세상은 간단하지 않다. 그리고, 데이터는 가끔 field를 누락하고, 명시적으로 null이나 비어있는 배열을 포함한다. 이런 상황에 대처하기 위해, Elasticsearch는 null이나 누락된 값을 다루기 위한, 몇 가지 도구를 가지고 있다.

exists Queryedit

The first tool in your arsenal is the exists query. This query will return documents that have any value in the specified field. Let’s use the tagging example and index some example documents:

첫 번째 도구는 exists query이다. 이 query는 지정한 field에 어떤 값을 가지는, document를 반환한다. 몇 개의 document를 색인하고, tagging 예제를 사용해 보자

POST /my_index/posts/_bulk
{ "index": { "_id": "1"              }}
{ "tags" : ["search"]                }  
{ "index": { "_id": "2"              }}
{ "tags" : ["search", "open_source"] }  
{ "index": { "_id": "3"              }}
{ "other_field" : "some data"        }  
{ "index": { "_id": "4"              }}
{ "tags" : null                      }  
{ "index": { "_id": "5"              }}
{ "tags" : ["search", null]          }  

tags field는 하나의 값을 가지고 있다.

tags field는 두 개의 값을 가지고 있다.

tags field는 완전히 누락되었다.

tags field는 null 로 설정되었다.

tags field는 하나의 값과 null 을 가지고 있다.

The resulting inverted index for our tags field will look like this:

tags field에 대한 inverted index의 결과는 아래와 같다.

Token

DocIDs

open_source

2

search

1,2,5

Our objective is to find all documents where a tag is set. We don’t care what the tag is, so long as it exists within the document. In SQL parlance, we would use an IS NOT NULL query:

tag가 설정된 모든 document를 찾는 것이 목적이다. document내에 태그가 존재하는 한, 태그가 무엇이든 관계없다. SQL에서는 IS NOT NULL 을 사용할 수 있다.

SELECT tags
FROM   posts
WHERE  tags IS NOT NULL

In Elasticsearch, we use the exists query:

Elasticsearch에서는 exists query를 사용한다.

GET /my_index/posts/_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "exists" : { "field" : "tags" }
            }
        }
    }
}

Our query returns three documents:

query는 3개의 document를 반환한다.

"hits" : [
    {
      "_id" :     "1",
      "_score" :  1.0,
      "_source" : { "tags" : ["search"] }
    },
    {
      "_id" :     "5",
      "_score" :  1.0,
      "_source" : { "tags" : ["search", null] } 
    },
    {
      "_id" :     "2",
      "_score" :  1.0,
      "_source" : { "tags" : ["search", "open source"] }
    }
]

document 5는 null 값을 가지고 있지만 반환된다. 실제 값, 태그가 색인되었기 때문에 field는 존재한다. 따라서 null 은 filter에 아무런 영향을 끼치지 않는다.

The results are easy to understand. Any document that has terms in the tags field was returned as a hit. The only two documents that were excluded were documents 3 and 4.

결과는 이해하기 쉽다. tags field에 단어를 가지고 있는 모든 document가 hit로 반환된다. 제외된 document는 3과 4뿐이다.

missing Queryedit

The missing query is essentially the inverse of exists: it returns documents where there is no value for a particular field, much like this SQL:

missing query는 기본적으로 exists 의 반대이다. 특정 filed에 아무런 값이 없는 document가 반환된다. 아래 SQL과 매우 유사하다.

SELECT tags
FROM   posts
WHERE  tags IS NULL

Let’s swap the exists query for a missing query from our previous example:

위의 예제에서 exists query를 missing query로 바꾸어 보자.

GET /my_index/posts/_search
{
    "query" : {
        "constant_score" : {
            "filter": {
                "missing" : { "field" : "tags" }
            }
        }
    }
}

And, as you would expect, we get back the two docs that have no real values in the tags field—documents 3 and 4:

기대했던 대로, tags field에 실제로 어떤 값도 존재하지 않는, 2개(3과 4)의 document를 반환한다.

"hits" : [
    {
      "_id" :     "3",
      "_score" :  1.0,
      "_source" : { "other_field" : "some data" }
    },
    {
      "_id" :     "4",
      "_score" :  1.0,
      "_source" : { "tags" : null }
    }
]

exists/missing on Objectsedit

The exists and missing queries also work on inner objects, not just core types. With the following document

exists 와 missing query는 기본(core) type이 아닌 inner 오브젝트에서도 동작한다. 아래 document를 보면,

{
   "name" : {
      "first" : "John",
      "last" :  "Smith"
   }
}

you can check for the existence of name.first and name.last but also just name. However, in Types and Mappings, we said that an object like the preceding one is flattened internally into a simple field-value structure, much like this:

name 뿐만 아니라 name.first 와 name.last 의 존재를 확인할 수 있다. 그러나, Types and Mappings에서, 위와 같은 오브젝트는, 아래처럼 단순한 field-value 구조로, 내부적으로 평면적이 된다고 이야기 했었다.

{
   "name.first" : "John",
   "name.last"  : "Smith"
}

So how can we use an exists or missing query on the name field, which doesn’t really exist in the inverted index?

그렇다면, 실제로 inverted index에 존재하지 않는 name field에, exists 나 missing query를 어떻게 사용할 수 있을까?

The reason that it works is that a filter like

그 이유는, 아래와 같은 filter는

{
    "exists" : { "field" : "name" }
}

is really executed as

실제로 아래와 같이 실행되기 때문이다.

{
    "bool": {
        "should": [
            { "exists": { "field": "name.first" }},
            { "exists": { "field": "name.last" }}
        ]
    }
}

That also means that if first and last were both empty, the name namespace would not exist.

즉, first 와 last 가 모두 비어 있다면, name namespace는 존재하지 않는 것이다.


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

2-1-3. Finding Multiple Exact Values  (0) 2017.09.30
2-1-4. Ranges  (0) 2017.09.30
2-1-6. All About Caching  (0) 2017.09.30
2-2. Full-Text Search  (0) 2017.09.30
2-2-1. Term-Based Versus Full-Text  (0) 2017.09.30