2015-04-22 2 views
1

Наша модель Account имеет first_name, last_name и ssn (номер социального страхования).Elasticsearch по нескольким полям с частичными и полными совпадениями

Я хочу сделать частичные совпадения на first_name, last_name ', но точное совпадение на ssn. У меня это до сих пор:

settings analysis: { 
    filter: { 
     substring: { 
     type: "nGram", 
     min_gram: 3, 
     max_gram: 50 
     }, 
     ssn_string: { 
     type: "nGram", 
     min_gram: 9, 
     max_gram: 9 
     }, 
    }, 
    analyzer: { 
     index_ngram_analyzer: { 
     type: "custom", 
     tokenizer: "standard", 
     filter: ["lowercase", "substring"] 
     }, 
     search_ngram_analyzer: { 
     type: "custom", 
     tokenizer: "standard", 
     filter: ["lowercase", "substring"] 
     }, 
     ssn_ngram_analyzer: { 
     type: "custom", 
     tokenizer: "standard", 
     filter: ["ssn_string"] 
     }, 
    } 
    } 

    mapping do 
    [:first_name, :last_name].each do |attribute| 
     indexes attribute, type: 'string', 
         index_analyzer: 'index_ngram_analyzer', 
         search_analyzer: 'search_ngram_analyzer' 
    end 

    indexes :ssn, type: 'string', index: 'not_analyzed' 

    end 

Мой поиск выглядит следующим образом:

query: { 
    multi_match: { 
    fields: ["first_name", "last_name", "ssn"], 
    query: query, 
    type: "cross_fields", 
    operator: "and" 
    } 

}

Так это работает:

Account.search("erik").records.to_a 

и даже (для Эрика Смита):

Account.search("erik smi").records.to_a 

и ПЛА:

Account.search("111112222").records.to_a 

но не:

Account.search("erik 111112222").records.to_a 

Любая идея, если я индексирование или запрашивая неправильно?

Благодарим за помощь!

ответ

1

Нужно ли это делать с помощью одной строки запроса? Если нет, то я хотел бы сделать что-то вроде этого:

PUT /test_index 
{ 
    "settings": { 
     "number_of_shards": 1, 
     "analysis": { 
     "filter": { 
      "ngram_filter": { 
       "type": "ngram", 
       "min_gram": 2, 
       "max_gram": 20 
      } 
     }, 
     "analyzer": { 
      "ngram_analyzer": { 
       "type": "custom", 
       "tokenizer": "standard", 
       "filter": [ 
        "lowercase", 
        "ngram_filter" 
       ] 
      } 
     } 
     } 
    }, 
    "mappings": { 
     "doc": { 
     "_all": { 
      "enabled": true, 
      "index_analyzer": "ngram_analyzer", 
      "search_analyzer": "standard" 
     }, 
     "properties": { 
      "first_name": { 
       "type": "string", 
       "include_in_all": true 
      }, 
      "last_name": { 
       "type": "string", 
       "include_in_all": true 
      }, 
      "ssn": { 
       "type": "string", 
       "index": "not_analyzed", 
       "include_in_all": false 
      } 
     } 
     } 
    } 
} 

Обратите внимание на использование в _all field. Я включил first_name и last_name в _all, но не ssn, и ssn не анализируется вообще, так как я хочу делать точные совпадения с ним.

Я индексируется пару документов для иллюстрации:

POST /test_index/doc/_bulk 
{"index":{"_id":1}} 
{"first_name":"Erik","last_name":"Smith","ssn":"111112222"} 
{"index":{"_id":2}} 
{"first_name":"Bob","last_name":"Jones","ssn":"123456789"} 

Тогда я могу запросить для частичных имен, и фильтр по точному ССН:

POST /test_index/doc/_search 
{ 
    "query": { 
     "filtered": { 
     "query": { 
      "match": { 
       "_all": { 
        "query": "eri smi", 
        "operator": "and" 
       } 
      } 
     }, 
     "filter": { 
      "term": { 
       "ssn": "111112222" 
      } 
     } 
     } 
    } 
} 

И я вернусь, что я м ожидающих:

{ 
    "took": 2, 
    "timed_out": false, 
    "_shards": { 
     "total": 1, 
     "successful": 1, 
     "failed": 0 
    }, 
    "hits": { 
     "total": 1, 
     "max_score": 0.8838835, 
     "hits": [ 
     { 
      "_index": "test_index", 
      "_type": "doc", 
      "_id": "1", 
      "_score": 0.8838835, 
      "_source": { 
       "first_name": "Erik", 
       "last_name": "Smith", 
       "ssn": "111112222" 
      } 
     } 
     ] 
    } 
} 

Если вам нужно выполнить поиск с помощью одной строки запроса (без фильтра) r), вы можете включить ssn в поле all, но с этой настройкой он также будет совпадать с частичными строками (например, 111112), так что это может быть не то, что вы хотите.

Если вы хотите только сопоставить префиксы (например, поисковые запросы, начинающиеся с начала слов), вы должны использовать edge ngrams.

я написал сообщение в блоге об использовании ngrams, которые могут помочь вам немного: http://blog.qbox.io/an-introduction-to-ngrams-in-elasticsearch

Вот код, который я использовал для этого ответа.Я пробовал несколько разных вещей, включая настройку, которую я разместил здесь, а другой в том числе ssn в _all, но с краевыми ngrams. Надеюсь, что это помогает:

http://sense.qbox.io/gist/b6a31c929945ef96779c72c468303ea3bc87320f

+0

Большое вам спасибо за ваш ответ - ничего себе. Я это попробую. Я думаю, это тоже сработало: как только я вынул «search_analyzer:« search_ngram_analyzer », он работает (до сих пор с тестами, которые я сделал). –

Смежные вопросы