본문 바로가기

Elasticsearch

[elasticsearch] match_all, match, match_phrase 사용 방법 및 차이점

반응형

match_all, match, match_phrase 사용 방법 및 차이점

 

실습 전, 준비사항 

test_index에 먼저 bulk로 데이터 입력해주기 & kibana 

POST test_index/_bulk
{"index": {"_id":1}}
{"message": "The little cute cat" }
{"index": {"_id":2}}
{"message": "The little cute cat eats the red fish" }
{"index": {"_id":3}}
{"message": "The little cute cat eats the brown fish" }
{"index": {"_id":4}}
{"message": "The cute cat little fish" }
{"index": {"_id":5}}
{"message": "the red fish" }

 

 

 

match_all 

match_all은 조건 아무것도 없이 해당 인덱스의 모든 데이터를 검색한다. 

GET test_index/_search
{
  "query": {
    "match_all": {}
  }
}

GET test_index/_search

kibana에서 모든 데이터를 검색할 때 /_search를 사용하는데 이와 동일하다. 

 

 

 

match

Elasticsearch의 풀 텍스트 검색에 가장 보편적으로 사용되는 match query는 말 그대로 "매칭"되는 것을 검색한다. 

GET test_index/_search
{
  "query": {
    "match": {
      "message": "cat"
    }
  }
}

"query"는 항상 써주어야하고 "message" 필드에 "cat"이 포함된 결과들을 보여준다. 

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 0.32575765,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.32575765,
        "_source" : {
          "message" : "The little cute cat"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.30086955,
        "_source" : {
          "message" : "The cute cat little fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.24476817,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.24476817,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      }
    ]
  }
}

cat 이 포함된 도큐먼트 총 4개가 나왔다. 

첫번째가 두번째보다 점수가 높은 이유는 message 필드의 데이터 길이가 더 짧을 수록 점수가 높게 매겨지기 때문이다. 

 

 

match "OR" 

match query에서 "op" operator 사용하는 방법은 간단하게 스페이스만 추가해주면 된다. 

GET test_index/_search
{
  "query": {
    "match": {
      "message": "cat fish"
    }
  }
}

GET test_index/_search
{
  "query": {
    "match": {
      "message": {
        "query": "cat fish",
        "operator": "or"
      }
    }
  }
}

또는 위와 같이 opderator 를 입력해준다. 

 

쿼리를 실행하면 cat 또는 fish 둘 중 하나라도 포함된 도큐먼트를 모두 검색한다. 

{
  "took" : 56,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 0.6017391,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.6017391,
        "_source" : {
          "message" : "The cute cat little fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.35513458,
        "_source" : {
          "message" : "the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.32575765,
        "_source" : {
          "message" : "The little cute cat"
        }
      }
    ]
  }
}

=> 검색 결과는 5개 전체가 나왔다. 

 

 

match "AND"

위에서 사용한 Operator에 "or" -> "and"로만 바꿔주면 된다. 

GET test_index/_search
{
  "query": {
    "match": {
      "message": {
        "query": "cat fish",
        "operator": "and"
      }
    }
  }
}

 

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.6017391,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.6017391,
        "_source" : {
          "message" : "The cute cat little fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.48953635,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      }
    ]
  }
}

=> 결과는 message필드에 cat과 fish를 모두 포함하고 있는 총 3개의 도큐먼트가 나온다. 

 

 

 

match_phrase 

match_all 은 전체 검색, match는 매칭되는 데이터 검색, match_phrase는 정확한 phrase "구문"을 검색한다. 

GET test_index/_search
{
  "query":{
    "match_phrase": {
      "message": "cat eats the red"
    }
  }
}

message 필드에 정확히 "cat eats the red"라는 문구가 있는 데이터를 검색한다. 

 

결과 

{
  "took" : 59,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.8085477,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.8085477,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      }
    ]
  }
}

 

 

match_phrase의 slop 옵션 

slop = 1 을 주면 주어진 쿼리의 빈 값에 1 만큼의 다른 단어가 존재해도 괜찮다. 

 

GET test_index/_search
{
  "query": {
    "match_phrase": {
      "message": {
        "query": "the fish",
        "slop": 1
      }
    }
  }
}

최우선적으로 "the fish" 정확한 데이터가 검색되고 그 다음 "the" + _______ +  "fish" 이렇게 있는 데이터가 검색된다. doc5 의 the little fish 를 -> the fish로 수정해서 검색한 결과는 

{
  "took" : 539,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.41782776,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.41782776,
        "_source" : {
          "message" : "the fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.15482008,
        "_source" : {
          "message" : "The little cute cat eats the red fish"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.15482008,
        "_source" : {
          "message" : "The little cute cat eats the brown fish"
        }
      }
    ]
  }
}

=> 요렇게 나온다! 

 

검색 쿼리가 "the little cat"이고 slop = 1 이라면 " " 스페이스 값(?) 빈 스트링 값 (?) 이 있는 곳 중 1 곳만 다른 단어가 들어오는 데이터를 검색한다. 

ex1. the very little cat  ----- ok

ex2. the little cute cat ----- ok

ex3. the very little cute cat ----- X 

 

만약 slop = 2 로 하면 위의 3번째 예시도 가능하다. 2번 slop을 할 수 있으니 ! 

 

 

 

결론 : 

모든 검색결과는 - match_all 을,

매칭되는 검색 또는 교집합/합집합 검색결과는 match 사용

정확한 String값 매칭 - match_phrase 사용하기 !

 

 

 

Reference : https://esbook.kimjmin.net/05-search/5.1-query-dsl

 

5.1 풀 텍스트 쿼리 - Full Text Query - Elastic 가이드북

검색어가 여럿일 때 검색 조건을 OR 가 아닌 AND 로 바꾸려면 operator 옵션을 사용할 수 있습니다. 이 경우 문법이 조금 달라지는데, <필드명>:<검색어> 형식으로 하던 것을 <필드명>: { "query":<검색어>

esbook.kimjmin.net

 

반응형