[elasticsearch] ElasticSearch로 단어의 일부를 검색하는 방법

최근에 ElasticSearch를 사용하기 시작했으며 단어의 일부를 검색 할 수 없습니다.

예 : ElasticSearch에서 색인을 생성 한 couchdb의 세 가지 문서가 있습니다.

{
  "_id" : "1",
  "name" : "John Doeman",
  "function" : "Janitor"
}
{
  "_id" : "2",
  "name" : "Jane Doewoman",
  "function" : "Teacher"
}
{
  "_id" : "3",
  "name" : "Jimmy Jackal",
  "function" : "Student"
}

이제 “Doe”가 포함 된 모든 문서를 검색하고 싶습니다.

curl http://localhost:9200/my_idx/my_type/_search?q=Doe

어떤 히트도 반환하지 않습니다. 하지만 내가 검색하면

curl http://localhost:9200/my_idx/my_type/_search?q=Doeman

하나의 문서 (John Doeman)를 반환합니다.

인덱스의 속성으로 다른 분석기와 다른 필터를 설정하려고했습니다. 또한 전체 쿼리를 사용하여 시도했습니다 (예 :

{
  "query": {
    "term": {
      "name": "Doe"
    }
  }
}

) 그러나 아무것도 작동하지 않는 것 같습니다.

“Doe”를 검색 할 때 ElasticSearch에서 John Doeman과 Jane Doewoman를 모두 찾도록하려면 어떻게해야합니까?

최신 정보

Igor가 제안한 것처럼 nGram 토크 나이저와 필터를 다음과 같이 사용하려고했습니다.

{
  "index": {
    "index": "my_idx",
    "type": "my_type",
    "bulk_size": "100",
    "bulk_timeout": "10ms",
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "tokenizer": "my_ngram_tokenizer",
          "filter": [
            "my_ngram_filter"
          ]
        }
      },
      "filter": {
        "my_ngram_filter": {
          "type": "nGram",
          "min_gram": 1,
          "max_gram": 1
        }
      },
      "tokenizer": {
        "my_ngram_tokenizer": {
          "type": "nGram",
          "min_gram": 1,
          "max_gram": 1
        }
      }
    }
  }
}

내가 지금 가지고있는 문제는 각각의 모든 쿼리가 모든 문서를 반환한다는 것입니다. 어떤 포인터? nGram 사용에 대한 ElasticSearch 설명서는 훌륭하지 않습니다 …



답변

nGram도 사용하고 있습니다. 표준 토크 나이저와 nGram을 필터로 사용합니다. 내 설정은 다음과 같습니다.

{
  "index": {
    "index": "my_idx",
    "type": "my_type",
    "analysis": {
      "index_analyzer": {
        "my_index_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "mynGram"
          ]
        }
      },
      "search_analyzer": {
        "my_search_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "standard",
            "lowercase",
            "mynGram"
          ]
        }
      },
      "filter": {
        "mynGram": {
          "type": "nGram",
          "min_gram": 2,
          "max_gram": 50
        }
      }
    }
  }
}

최대 50 자의 단어 부분을 찾아 봅시다. 필요한만큼 max_gram을 조정하십시오. 독일어로 말하면 실제로 커질 수 있으므로 높은 값으로 설정했습니다.


답변

큰 색인에서 선행 및 후행 와일드 카드를 사용한 검색은 매우 느립니다. 단어 접두사로 검색하려면 선행 와일드 카드를 제거하십시오. 단어 중간에 부분 문자열을 실제로 찾으려면 ngram 토크 나이저를 사용하는 것이 좋습니다.


답변

매핑을 변경할 필요가 없다고 생각합니다. query_string을 사용해보십시오 . 완벽합니다. 모든 시나리오는 기본 표준 분석기에서 작동합니다.

데이터가 있습니다 :

{"_id" : "1","name" : "John Doeman","function" : "Janitor"}
{"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"}

시나리오 1 :

{"query": {
    "query_string" : {"default_field" : "name", "query" : "*Doe*"}
} }

응답:

{"_id" : "1","name" : "John Doeman","function" : "Janitor"}
{"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"}

시나리오 2 :

{"query": {
    "query_string" : {"default_field" : "name", "query" : "*Jan*"}
} }

응답:

{"_id" : "1","name" : "John Doeman","function" : "Janitor"}

시나리오 3 :

{"query": {
    "query_string" : {"default_field" : "name", "query" : "*oh* *oe*"}
} }

응답:

{"_id" : "1","name" : "John Doeman","function" : "Janitor"}
{"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"}

편집-스프링 데이터 탄성 검색과 동일한 구현
https://stackoverflow.com/a/43579948/2357869

query_string이 다른 것보다 더 나은 방법에 대한 또 다른 설명 https : //.com/a/43321606/2357869


답변

인덱스 매핑을 변경하지 않으면 원하는 부분 검색을 수행하는 간단한 접두사 쿼리를 수행 할 수 있습니다

즉.

{
  "query": {
    "prefix" : { "name" : "Doe" }
  }
}

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html


답변

여기에 설명 된 솔루션을 사용해보십시오 : ElasticSearch의 정확한 하위 문자열 검색

{
    "mappings": {
        "my_type": {
            "index_analyzer":"index_ngram",
            "search_analyzer":"search_ngram"
        }
    },
    "settings": {
        "analysis": {
            "filter": {
                "ngram_filter": {
                    "type": "ngram",
                    "min_gram": 3,
                    "max_gram": 8
                }
            },
            "analyzer": {
                "index_ngram": {
                    "type": "custom",
                    "tokenizer": "keyword",
                    "filter": [ "ngram_filter", "lowercase" ]
                },
                "search_ngram": {
                    "type": "custom",
                    "tokenizer": "keyword",
                    "filter": "lowercase"
                }
            }
        }
    }
}

디스크 사용 문제와 너무 긴 검색어 문제를 해결하기 위해 짧은 8 자 길이의 ngram 이 사용됩니다 ( “max_gram”: 8으로 구성 ). 8자를 초과하는 용어를 검색하려면 해당 문자열에서 고유 한 8 문자 하위 문자열을 모두 찾는 부울 AND 쿼리로 검색을 바꾸십시오. 예를 들어, 사용자가 큰 마당 (10 자 문자열)을 검색하면 다음과 같이 검색됩니다.

“arge ya and arge yar AND rge yard .


답변

자동 완성 기능을 구현하려면 완료 제안자 가 가장 깔끔한 솔루션입니다. 다음 블로그 게시물 에는 이것이 어떻게 작동하는지 매우 명확하게 설명되어 있습니다.

즉, 유효한 제안을 포함하고 빠른 검색 및 메모리 사용에 최적화 된 FST라는 메모리 내 데이터 구조입니다. 본질적으로 이것은 단지 그래프 일뿐입니다. 단어를 포함하는 인스턴스 및 FST를 들어 hotel, marriot, mercure, munchenmunich같을 것이다 :

여기에 이미지 설명을 입력하십시오


답변

regexp를 사용할 수 있습니다.

{ "_id" : "1", "name" : "John Doeman" , "function" : "Janitor"}
{ "_id" : "2", "name" : "Jane Doewoman","function" : "Teacher"  }
{ "_id" : "3", "name" : "Jimmy Jackal" ,"function" : "Student"  }

이 쿼리를 사용하는 경우 :

{
  "query": {
    "regexp": {
      "name": "J.*"
    }
  }
}

이름이 “J”로 시작하는 모든 데이터를 제공합니다. 이름이 “man”으로 끝나는 처음 두 레코드 만 수신하려고하므로이 쿼리를 사용할 수 있습니다.

{
  "query": {
    "regexp": {
      "name": ".*man"
    }
  }
}

이름이 “m”인 모든 레코드를 수신하려면이 쿼리를 사용할 수 있습니다.

{
  "query": {
    "regexp": {
      "name": ".*m.*"
    }
  }
}

이것은 저에게 효과적이며 내 대답이 귀하의 문제를 해결하기에 적합하기를 바랍니다.