-
[ELK Stack]Elasticsearch 검색 - Full Text QueryELK Stack 2020. 12. 1. 18:59반응형
여기에서도 제가 사용한 부분에 대해서만 설명하겠습니다.
Official 문서에 detail 하게 설명되어 있기 때문에 아래에서는 주의 할점만 언급하도록 하겠습니다.
www.elastic.co/guide/en/elasticsearch/reference/current/full-text-queries.html
Full text queries | Elasticsearch Reference [7.10] | Elastic
The full text queries enable you to search analyzed text fields such as the body of an email. The query string is processed using the same analyzer that was applied to the field during indexing. The queries in this group are: intervals query A full text qu
www.elastic.co
하기와 같이 test index와 document를 생성합니다.
PUT /test_query/_doc/1 { "title": "Match", "content": "Returns documents that match a provided text, number, date or boolean value. The provided text is analyzed before matching." } PUT /test_query/_doc/2 { "title": "Multi Match", "content": "The multi match query builds on the match query to allow multi-field queries" } PUT /test_query/_doc/2 { "title": "MultiMatch", "content": "The multi match query builds on the match query to allow multi-field queries" }
Elasticsearch에서 text는 token 기반으로 검색이 되기 때문에 text가 어떤 token으로 분해(?)되는지를 알아야 할 때가 있습니다. token은 하기와 같이 확인 할 수 있습니다.
POST /test_query/_analyze?pretty { "text": "MultiMatch" } { "tokens" : [ { "token" : "multimatch", "start_offset" : 0, "end_offset" : 10, "type" : "<ALPHANUM>", "position" : 0 } ] }
Match
match는 말그대로 검색하는 문구가 존재하는 item을 찾아서 return 하는것입니다.
주의할점은 match는 "*mat*" 와 같은 부분검색이 되지 않습니다. token 기준으로 검색하게 되기때문에 하기와 같이 검색시 title이 "MultiMatch" 인 item은 검색되지 않습니다.
또한 match에서는 query 문구가 token으로 transform 한 후 default로 "OR" 조건으로 검색합니다. "AND" 조건으로 바꾸고 싶다면 operator 값을 "AND"로 변경하면 됩니다.
GET /test_query/_search { "query": { "match": { "title": "match" } } } "hits" : [ { "_index" : "test_query", "_type" : "_doc", "_id" : "1", "_score" : 0.52354836, "_source" : { "title" : "Match", "content" : "Returns documents that match a provided text, number, date or boolean value. The provided text is analyzed before matching." } } ]
Multi-Match
Match는 한개 field에서밖에 검색이 안됩니다. 여러개 field에서 동일한 문구로 검색하려고 하면 multi-match를 사용해야 합니다.
검색 field에 (^) notation을 추가하면 해당 field 검색이 boost(relevance score 계산시 우대를 받게 됨)를 얻게 됩니다. notation이 있을 때와 없을 때 score를 비교해보면 바로 알수 있을것입니다.
GET /test_query/_search { "query": { "multi_match": { "fields": ["title^3", "content"], "query": "match" } } }
추가로 multi_match 에서 여러개 field 검색이 어떻게 조합되는지를 보겠습니다. 조합방식은 여러가지가 있지만 제가 사용해본 best_fields와 most_fields만 보겠습니다.
best_fields:
default로 best_fields로 검색이 됩니다.
best fields는 multi-match를 dis_max query로 변경하여 검색하게 됩니다. 위의 multi-match query는 하기와 같이 변경되어 실행됩니다.
GET /test_query/_search { "query": { "dis_max": { "queries": [ {"match": {"title": {"query": "match", "boost": 3}}}, {"match": {"content": "match"}} ] } } }
most_fields:
type을 most_fields로 설정하면 하기와 같이 boolean should query로 변경되어 검색하게 됩니다.
GET /test_query/_search { "query": { "multi_match": { "fields": ["title^3", "content"], "type": "most_fields", "query": "match" } } } GET /test_query/_search { "query": { "bool": { "should": [ {"match": {"title": {"query": "match", "boost": 3}}}, {"match": {"content": "match"}} ] } } }
필요에 맞춰서 type을 지정해서 사용해야 합니다. 추가로 match를 사용하기 때문에 mult-match도 wildcard 검색이 되지 않습니다.Query String
"*match*" 와 같이 검색하려고 하면 query_string을 사용하면 됩니다. query string은 wildcard 검색이 되기 때문에 부분검색이 되는것입니다. 하기와 같이 query_string으로 검색하면 "MultiMatch"도 검색결과에 포함됩니다.
GET /test_query/_search { "query": { "query_string": { "fields": ["title"], "query": "*match*" } } } "hits" : [ { "_index" : "test_query", "_type" : "_doc", "_id" : "1", "_score" : 1.0, "_source" : { "title" : "Match", "content" : "Returns documents that match a provided text, number, date or boolean value. The provided text is analyzed before matching." } }, { "_index" : "test_query", "_type" : "_doc", "_id" : "2", "_score" : 1.0, "_source" : { "title" : "MultiMatch", "content" : "The multi match query builds on the match query to allow multi-field queries" } } ]
검색 조건에서 볼수 있다시피 fields를 설정할 수 있어서 multi field 검색도 됩니다.
Official 문서를 보면 query string을 사용시 검색문구에 invalid syntax가 들어있으면 error를 return 하게 됨으로 검색box에서 가급적으로 사용하지 말라고 합니다. 그런데 "*match*"와 같이 부분검색을 추가설정없이 간편하게 사용할 수 있는 full text query는 없습니다. 따라서 저는 검색문구에서 특수문자를 제거한 후 query하도록 구현하였습니다.
좋은 자료.
text 검색에 대해 자료를 찾다가 하기 블로그를 보게 되었습니다. text query는 token 을 기준으로 검색을 하게됩니다. 영어는 단어별로 되어 있어서 괜찮은데 한글 검색시에는 text가 token으로 transform 한 결과에 따라 검색이 달라질 수 있습니다. 해당 현상에 대한 설명과 해당 문제를 해결하기 위해 ngram을 도입한 것에 대한 내용인데 많은 도움이 되었습니다. 참고하시기 바랍니다.
findstar.pe.kr/2018/07/14/elasticsearch-wildcard-to-ngram/
ElasticSearch 에서 wildcard 쿼리 대신 ngram을 활용하는 방법
ElasticSearch를 사용하면서 DSL 을 구성할 때, RDBMS 의 like "%keyword%" 와 같은 쿼리를 대체하기 위해서 wildcard 를 사용하는 경우를 몇번 목격하였다. 이 경우 원하는 결과를 제대로 얻을 수도 없을 뿐더
findstar.pe.kr
반응형'ELK Stack' 카테고리의 다른 글
[ELK Stack] Filebeat 소개 및 사용 (0) 2022.08.31 [ELK Stack] Elasticsearch cluster 롤링 업그레이드 관련(7.2 -> 7.17.2) (0) 2022.08.25 [ELK Stack] Elasticsearch 검색(search) - Compound Query (0) 2020.12.01 [ELK Stack] Elasticsearch 검색 - Highlight, Nested Field (0) 2020.10.20 [ELK Stack] [초보자] Logstash 시작하기 (0) 2020.10.18