Elasticsearch에서 생일을 축하하고 싶습니다.

17803 단어 Elasticsearch

Elasticsearch에서 생일을 축하하고 싶습니다.



@kaiba 이라고 합니다.

해마다 생일이 우울해졌습니다만, 「이번 달 생일을 맞이하는 사람」을 찾는 것 같은 케이스로 고생했기 때문에 기사로 해 보겠습니다.

TL;DR


  • 「이번 달 생일을 맞이하는 사람」을 찾는 방법은 몇개인가 있지만 달, 일을 index 하는 것이 좋을지도.

  • 공식 포럼 그럼
  • 다음 생일을 색인에 추가하는 방법 (정기적으로 색인 업데이트 필요)
  • script query를 쓰고 노력한다 (매우 유지하고 싶지 않은 느낌의 코드다…)


  • 해보자



    사용자의 생일을 보유한 서비스가 많다고 생각합니다.
    연월일을 입력해, DB에는 Date형으로 보관 유지하는 케이스가 많은 것은 아닐까요?
    우선 Elasticsearch에 그대로 넣어 보겠습니다.

    색인을 만듭니다. 이름은 birthday로 만들었습니다.
    curl -X PUT -H "Content-Type: application/json" http://b.lvh.me:9200/birthday
    

    문서를 넣습니다. 다음 문서를 준비했습니다.
    {
        "name": "kaiba",
        "birthday": "1992-12-05"
    }
    

    이름은 doc에서 ID 1로 넣었습니다.
    curl -X PUT -H "Content-Type: application/json" http://b.lvh.me:9200/birthday/doc/1?pretty -d @user.json
    

    데이터 형식을 확인해 둡니다. date가 되어 있네요.
    curl -X GET -H "Content-Type: application/json" http://b.lvh.me:9200/birthday/_mapping?pretty
    {
      "birthday" : {
        "mappings" : {
          "doc" : {
            "properties" : {
              "birthday" : {
                "type" : "date"
              },
              "name" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              }
            }
          }
        }
      }
    }
    

    Query를 생각해 보기


    birthday.month >= 12月 같은 것을 쓰면 좋을 것입니다! 라고 생각하고 있었습니다만, Elasicsearch라고 하면(자) 죄송합니다.
    공식 포럼 에 확실히 질문이 있었으므로 소개합니다.

    제안 1 다음 생일을 유지하십시오.


    1992-12-05 태생의 다음 생일은 2019-12-05 네요. 그것을 index 해두고 다음과 같이 찾습니다.
    {
        "query": {
            "range": {
               "next_birthday": {
                  "gte": "now",
                  "lte": "now+10d/d"
               }
            }
        }
    }
    

    쿼리를 이해하기 쉽습니다. Elasticsearch 같은 접근 방식으로 훌륭합니다!
    하지만 next_birthday 를 정기적으로 업데이트해야 합니다.
    언제 검색하는지에 따라 다르지만 대부분의 경우 매일 될 것 같습니다. 비용도 걱정됩니다.

    안2 script query로 열심히


    {
       "query": {
          "bool": {
             "must": {
                "script": {
                   "script": {
                      "inline": "def today = LocalDate.parse(params.today); 中略",
                      "lang": "painless",
                      "params": {
                         "today": "2017-01-09",
                         "daysFuture": 10
                      }
                   }
                }
             }
          }
       }
    }
    
    birthday.month >= 12月 같은 것을 쓰는 예입니다.
    painless의 script query를 쓰게 되어 유지하기 힘들고, 퍼포먼스도 나쁘다.
    Elasticsearch답지 않은 접근법에 느낍니다.

    내가 생각한 최강 생일 검색



    주제입니다. 이렇게 하는 것은 어떻습니까?
    생일의 달, 일을 다른 데이터로 index합니다.
    {
        "name": "kaiba",
        "birthday_month": 12,
        "birthday_day": 5
    }
    

    년을 넘는 경우는 또 번거로움이 필요하지만 어렵지는 않을 것입니다.
    {
        "query": {
            "bool": {
                "must": [
                    {
                        "range": {
                            "birthday_month": {
                                "gte": 12
                            }
                        }
                    },
                    {
                        "range": {
                            "birthday_day": {
                                "gte": 1,
                                "lte": 10
                            }
                        }
                    }
                ]
            }
        }
    }
    

    검색해 봅니다.
    curl -X POST -H "Content-Type: application/json" http://b.lvh.me:9200/birthday/_search\?pretty -d @search.json
    {
      "took" : 4,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 2.0,
        "hits" : [
          {
            "_index" : "birthday",
            "_type" : "doc",
            "_id" : "1",
            "_score" : 2.0,
            "_source" : {
              "name" : "kaiba",
              "birthday" : "1992-12-05",
              "birthday_month" : 12,
              "birthday_day" : 5
            }
          }
        ]
      }
    }
    

    LGTM!

    그리고는 다음의 케이스를 판단해, Es의 쿼리를 조립하면 좋다고 생각합니다. 필기로 죄송합니다.



    년과 달을 넘는 경우도 고려하는 경우는 또 한번 노력하네요.

    요약



    공식 포럼에 비해 다음이 좋을까라고 생각합니다.
  • 색인을 정기적으로 업데이트 할 필요가 없습니다
  • Query를 이해하기 쉽습니다
  • Elasticsearch 같은 접근법

  • 막상 이렇게 문장에 떨어뜨려 보면 「무엇을 그런 당연한 일을」이라고 생각할지도 모릅니다.
    저도 그렇습니다만 RDB에 익숙해지면 꽤 이런 발상을 할 수 없어 어렵게 생각해 버리는 일이 있네요.
    나처럼 곤란한 사람의 도움이 되도록, 포럼에 추기하고 싶습니다만, 할 수 없지요. 죄송합니다.

    좋은 웹페이지 즐겨찾기