ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ELK Stack] Elasticsearch 검색(search) - Compound Query
    ELK Stack 2020. 12. 1. 16:50
    반응형

    실제 사용한 부분에 대해서만 설명하겠습니다.

    먼저 하기와 같이 test에 사용하는 data를 생성하겠습니다.

    PUT /test_query/_doc/1
    {
      "sports": "football",
      "name": "Messi"
    }
    PUT /test_query/_doc/2
    {
      "sports": "football",
      "name": "Ibrahimovic"
    }
    PUT /test_query/_doc/3
    {
      "sports": "basketball",
      "name": "LeBron James"
    }
    
    PUT /test_query/_doc/4
    {
      "sports": "basketball",
      "name": "DF ER Nicole James basketball"
    }
    PUT /test_query/_doc/5
    {
      "sports": "James basketball",
      "name": "James Nicole Nicole Nicole James James James Nicole Nicole James"
    }

    혹시나 모르시는 분있을가봐 하는 얘기인데요, 하기 명령은 Kibana의 Dev Tools에서 실행할수 있습니다.

    www.elastic.co/guide/en/kibana/current/console-kibana.html

     

    Console | Kibana Guide [7.10] | Elastic

    You are unable to interact with the REST API of Kibana with the Console.

    www.elastic.co

    Boolean query

    여러가지 검색조건을 조합해서 검색합니다.

    • must: 검색결과에 해당 조건이 반드시 포함되어야 함. query context에서 동작함.
    • filter: 검색결과에 해당 조건이 반드시 포함되어야 함.
      • must와 다른점은 relevance score에 영향을 주지 않음. 해당 조건이 포함되어있는지 YES/NO 여부만 확인하기 때문에 filter는 속도가 빠름.
      • filter context에서 동작 함.
    • should: optional 조건임. 포함된 조건들이 검색결과에 포함될수도 있고 포함되지 않을수도 있음.
      • minimum_should_match 값을 설정하는 방법으로 should에 있는 조건이 검색결과에 포함될지를 결정할 수 있음. 검색조건에 should만 있으면 minimum_should_match 값이 default로 1이고 should외의 조건이 존재하면 minimum_should_match 값이 default로 0.
      • query context에서 동작함.
    • must_not: 해당 조건은 검색결과에 포함되지 말아야 함. filter와 마찬가지로 score에 영향을 주지 않음.

    하기 내용을 참조하였습니다.

    unuseful.tistory.com/21

     

    Elasticsearch context와 bool query 이야기

    필자는 Elasticsearch(이하 ES)를 기반으로 검색엔진 개발하는 일을 하고 있다. ES를 통해 검색엔진을 개발 하면서 글로 남기고픈 여러 주제들이 있었는데, 그 중 첫 번째로 bool query에 대해서 글을 남

    unuseful.tistory.com

    www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html

     

    Query and filter context | Elasticsearch Reference [7.10] | Elastic

    Use query clauses in query context for conditions which should affect the score of matching documents (i.e. how well does the document match), and use all other query clauses in filter context.

    www.elastic.co

    Boolean query에서 주의할점은 should와 filter/must_not을 결합하여 사용 시 minimum_should_match값을 고려해야 하는것입니다. 위에서 설명했듯이 should는 기타 조건과 조합하여 검색시 minimum_should_match 값이 default로 0으로 설정됩니다. 즉 검색결과에 should 의 그 어떤 조건에도 match되지 않는 결과들이 포함될수 있다는 것입니다.

    하기 query를 날려봅니다.

    GET /test_query/_search
    {
      "query": {
        "bool": {
          "should": [
            {"match": {
              "name": "Messi"
            }}
          ],
          "filter": [
            {"match": {
              "sports": "basketball"
            }}
          ]
        }
      }
    }

    얼핏보면(?), 일단 저는 검색결과에서 "name"이 "Messi" 인 결과에서 "sports"가 "basketball"로 되어있는 값을 가져오려고 위와 같이 작성하였습니다. 제 생각대로 하면 검색결과는 존재하지 않습니다. 그러나 실행해보면 하기와 같은 결과가 return됩니다.

    {
      "took" : 5,
      "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_query",
            "_type" : "_doc",
            "_id" : "3",
            "_score" : 0.0,
            "_source" : {
              "sports" : "basketball",
              "name" : "LeBron James"
            }
          }
        ]
      }
    }

    즉 should 조건이 무시되고 filter조건만 만족하는 결과가 return된것입니다. 

    위와 같은 의도로 검색하려면 하기와 같이 변경하면 됩니다.

    • minimum_should_match 값을 1로 변경
    • should match대신 must 를 사용
    GET /test_query/_search
    {
      "query": {
        "bool": {
          "should": [
            {"match": {
              "name": "Messi"
            }}
          ],
          "minimum_should_match": 1,
          "filter": [
            {"match": {
              "sports": "basketball"
            }}
          ]
        }
      }
    }
    
    GET /test_query/_search
    {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "name": "Messi"
            }}
          ],
          "filter": [
            {"match": {
              "sports": "basketball"
            }}
          ]
        }
      }
    }

    Constant score:

    만약 filter에 score를 주고 싶으면 constant_score를 사용하면 됩니다.

    GET /test_query/_search
    {
      "query": {
        "constant_score": {
          "filter": 
          {
            "match": {
              "sports": "basketball"
            } 
          },
          "boost": 1.0
        }
      }
    }
    
    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "3",
            "_score" : 1.0,
            "_source" : {
              "sports" : "basketball",
              "name" : "LeBron James"
            }
          }
        ]
      }
    }

    Disjunction max query

    여러개 query 조건이 있을 때 dis_max는 그 중 가 장 큰 relevance score를 최종 score로 사용합니다. 만약 tie_breaker가 설정이 되어 있으면 기타 조건의 score에 tie_breaker 값을 곱한후 최종 score에 plus 합니다.

    하기 두 query결과 값을 보면 쉽게 이해할 수 있습니다.

    (1). 첫번째는 boolean query의 must로 검색하였습니다. 정확하게 검색하는 "Nicole James basketball" 이라는 값이 존재하는 item(_id: 4)이 있음에도 (_id: 5) item이 score가 가장 높게 return 되었습니다.

    GET /test_query/_search
    {
      "query": {
        "bool": {
          "must": [
            {"match": {"sports": "Nicole James basketball"}},
            {"match": {"name": "Nicole James basketball"}}
          ]
        }
      }
    }
    
    "hits" : [
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "5",
            "_score" : 4.097313,
            "_source" : {
              "sports" : "James basketball",
              "name" : "James Nicole Nicole Nicole James James James Nicole Nicole James"
            }
          },
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "4",
            "_score" : 3.4452512,
            "_source" : {
              "sports" : "basketball",
              "name" : "DF ER Nicole James basketball"
            }
          },
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "3",
            "_score" : 1.564933,
            "_source" : {
              "sports" : "basketball",
              "name" : "LeBron James"
            }
          }
        ]

    (2). dis_max로 검색해 보겠습니다.

    GET /test_query/_search
    {
      "query": {
        "dis_max": {
          "queries": [
            {"match": {"sports": "Nicole James basketball"}},
            {"match": {"name": "Nicole James basketball"}}
          ]
        }
      }
    }
    
    "hits" : {
        "total" : {
          "value" : 3,
          "relation" : "eq"
        },
        "max_score" : 2.7090812,
        "hits" : [
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "4",
            "_score" : 2.7090812,
            "_source" : {
              "sports" : "basketball",
              "name" : "DF ER Nicole James basketball"
            }
          },
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "5",
            "_score" : 2.3688042,
            "_source" : {
              "sports" : "James basketball",
              "name" : "James Nicole Nicole Nicole James James James Nicole Nicole James"
            }
          },
          {
            "_index" : "test_query",
            "_type" : "_doc",
            "_id" : "3",
            "_score" : 0.8287628,
            "_source" : {
              "sports" : "basketball",
              "name" : "LeBron James"
            }
          }
        ]

    결과에서 보다시피 (_id: 4) item이 가장 높은 score를 가지고 있습니다. dis_max는 검색 조건중에서 가장 높은 score를 사용하기 때문에 위와 같은 결과를 받습니다. 추가로 dis_max 결과와 boolean query 결과의 score를 보면 값이 차이가 많이 나는 것을 확인할 수도 있습니다.

    검색하는 문구가 정확하게 포함되어 있는 결과의 score를 높이고 싶을 때 dis_max를 사용하면 좋을것 같습니다.

    다음 페이지에서는 full text query 관련해서 설명하겠습니다.

    2020/12/01 - [ELK Stack] - [ELK Stack] [초보자] Elasticsearch 검색(search) - Full Text Query

    반응형

    댓글

Designed by Tistory.