정확 검색과 스테밍 혼합
원본 보기정확 검색과 스테밍 혼합
검색 애플리케이션을 구축할 때 스테밍은 대개 필수입니다. skiing에 대한 쿼리가 ski나 skis를 포함한 문서와 매칭되기를 원하기 때문입니다. 그런데 사용자가 skiing만 정확히 검색하고 싶다면 어떻게 해야 할까요? 일반적인 방법은 multi-field를 사용해 같은 내용을 두 가지 다른 방식으로 색인하는 것입니다.
PUT index
{
"settings": {
"analysis": {
"analyzer": {
"english_exact": {
"tokenizer": "standard",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"properties": {
"body": {
"type": "text",
"analyzer": "english",
"fields": {
"exact": {
"type": "text",
"analyzer": "english_exact"
}
}
}
}
}
}
PUT index/_doc/1
{
"body": "Ski resort"
}
PUT index/_doc/2
{
"body": "A pair of skis"
}
POST index/_refresh
이렇게 설정하면 body에서 ski를 검색할 때 두 문서가 모두 반환됩니다.
GET index/_search
{
"query": {
"simple_query_string": {
"fields": [ "body" ],
"query": "ski"
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 2,
"relation": "eq"
},
"max_score": 0.18232156,
"hits": [
{
"_index": "index",
"_id": "1",
"_score": 0.18232156,
"_source": {
"body": "Ski resort"
}
},
{
"_index": "index",
"_id": "2",
"_score": 0.18232156,
"_source": {
"body": "A pair of skis"
}
}
]
}
}
반면 body.exact에서 ski를 검색하면 문서 1만 반환됩니다. body.exact의 분석 체인은 스테밍을 수행하지 않기 때문입니다.
GET index/_search
{
"query": {
"simple_query_string": {
"fields": [ "body.exact" ],
"query": "ski"
}
}
}
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.8025915,
"hits": [
{
"_index": "index",
"_id": "1",
"_score": 0.8025915,
"_source": {
"body": "Ski resort"
}
}
]
}
}
이 방식은 최종 사용자에게 그대로 노출하기 어렵습니다. 사용자가 정확 일치를 원하는지 아닌지 파악해 알맞은 필드로 전달할 방법이 필요하기 때문입니다. 게다가 쿼리의 일부만 정확히 매칭되어야 하고 나머지는 스테밍을 적용해야 한다면 어떻게 해야 할까요?
다행히 query_string과 simple_query_string 쿼리에는 바로 이 문제를 해결하는 기능인 quote_field_suffix가 있습니다. 이 기능은 따옴표 사이에 나타나는 단어를 다른 필드로 전달하라고 Elasticsearch에 알려줍니다. 아래를 참고하세요.
GET index/_search
{
"query": {
"simple_query_string": {
"fields": [ "body" ],
"quote_field_suffix": ".exact",
"query": "\"ski\""
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.8025915,
"hits": [
{
"_index": "index",
"_id": "1",
"_score": 0.8025915,
"_source": {
"body": "Ski resort"
}
}
]
}
}
위 사례에서 ski는 따옴표 사이에 있었기 때문에 quote_field_suffix 파라미터에 의해 body.exact 필드에서 검색되었고, 그래서 문서 1만 매칭되었습니다. 이를 통해 사용자는 정확 검색과 스테밍 검색을 원하는 대로 혼합할 수 있습니다.
quote_field_suffix에 전달한 필드가 존재하지 않으면 검색은 쿼리 문자열의 기본 필드를 사용하는 방식으로 폴백합니다.