2015-05-28 23 views
11

ElasticSearch, analiz alanlarındaki tam eşlemeleri tanımlamanın bir yolu var mı? İdeal olarak, dokümanlarımı küçültmek, belirtmek, saplamak ve hatta belki de fonetikleştirmek istiyorum, daha sonra "kesin" eşleşmeleri sorgular.Elasticsearch, analiz alanlarındaki tam eşlemeler

Demek istediğim, "Hamburger Çöreği" ve "Hamburger" leri indekslersem ["hamburger", "çörek"] ve ["hamburger"] olarak analiz edilir. "Hamburger" için arama yaparsam, "kesin" eşleşme olduğu için yalnızca "hamburger" belgesini iade eder.

Anahtar sözcük belirtecini kullanmayı denedim, ancak bu, bireysel belirteçlerin kullanılmasına neden olmaz. Jeton sayısının eşit olduğundan emin olmak için bir şeyler yapmam gerekir mi?

Çok alanları biliyorum ve "not_analyzed" türünü kullanıyorum ama bu aradığımdan daha kısıtlayıcı. Tam eşleme, analiz sonrası istiyorum.

cevap

9

Zona belirteçleri ile birlikte ve istediğiniz başka şeyleri kullanın. token_count türünde, alandaki simge sayısını sayan bir alt alan ekleyin.

Arama sırasında, arama metninde belirttiğiniz simge sayısıyla dizindeki belirteçlerin sayısıyla eşleştirmek için ek bir filtre eklemeniz gerekir. Gerçek aramayı gerçekleştirdiğinizde, arama dizesindeki belirteçleri sayması gereken ek bir adımın olması gerekir. Bu şunun gibi: zona tonları çoklu belirteçler oluşturacak ve arama metninizin boyutuyla eşleştiğinden emin olmalısınız.

{ 
    "settings": { 
    "analysis": { 
     "filter": { 
     "filter_shingle": { 
      "type": "shingle", 
      "max_shingle_size": 10, 
      "min_shingle_size": 2, 
      "output_unigrams": true 
     }, 
     "filter_stemmer": { 
      "type": "porter_stem", 
      "language": "_english_" 
     } 
     }, 
     "analyzer": { 
     "ShingleAnalyzer": { 
      "tokenizer": "standard", 
      "filter": [ 
      "lowercase", 
      "snowball", 
      "filter_stemmer", 
      "filter_shingle" 
      ] 
     } 
     } 
    } 
    }, 
    "mappings": { 
    "test": { 
     "properties": { 
     "text": { 
      "type": "string", 
      "analyzer": "ShingleAnalyzer", 
      "fields": { 
      "word_count": { 
       "type": "token_count", 
       "store": "yes", 
       "analyzer": "ShingleAnalyzer" 
      } 
      } 
     } 
     } 
    } 
    } 
} 

Ve sorgu: o jeton kombinasyonları oluşturabilir çünkü

{ 
    "query": { 
    "filtered": { 
     "query": { 
     "match_phrase": { 
      "text": { 
      "query": "HaMbUrGeRs BUN" 
      } 
     } 
     }, 
     "filter": { 
     "term": { 
      "text.word_count": "2" 
     } 
     } 
    } 
    } 
} 

shingles filtre Burada önemli olan

Bunun bir girişimde, sadece size bir fikir vermek için. Ve bundan daha fazlası, bunlar emri veya jetonları tutan kombinasyonlardır. Imo, burada yerine getirilmesinin en zor şartı, belirteçlerin değiştirilmesi, (kökten çıkarılması, küçültülmesi vb.) Ve orijinal metni tekrar birleştirmektir. Kendi "birleştirme" filtresini tanımlamadıkça, shingles filtresini kullanmaktan başka bir yol olduğunu düşünmüyorum.

shingles ile başka bir sorun var: gerekmeyen kombinasyonlar oluşturur.

Eğer tam anlamını eşleşen söz konusu belgelerde ilgileniyorsanız
  "angeles", 
      "buns", 
      "buns in", 
      "buns in los", 
      "buns in los angeles", 
      "hamburgers", 
      "hamburgers buns", 
      "hamburgers buns in", 
      "hamburgers buns in los", 
      "hamburgers buns in los angeles", 
      "in", 
      "in los", 
      "in los angeles", 
      "los", 
      "los angeles" 

, belgeler Yukarıdaki "hamburger çörekler içinde aradığınızda, yalnızca eşleşir: "Hamburgers buns in Los Angeles" gibi bir metni için size zona uzun bir liste ile sona los angeles "(ve herhangi bir hamburger çöreği" los angeles "gibi) ile eşleşmiyorsa o zaman uzun zona listesini filtrelemenin bir yoluna ihtiyacınız var. Gördüğüm yol word_count kullanmaktır.

+0

Zonaların amacı nedir? – abroekhof

+0

Ayrıca, Porter ve Kartopu stemmer kullanmanın bir nedeni var mı? – abroekhof

+0

Nedeni yok. Bu, benim sadece bazı gerçek kodları göstermek için hızla değiştirdiğim ve değiştirebileceğim bir örnek. Önemli parçalar 'shingle' filtresi,' token_count' tipi alan ve sorgulamanın kendisidir. Filtrelerin geri kalanı sadece örnek: bunlar dışarı alınabilir, diğer şeyler eklenebilir. –

3

Bu işlem için multi-fields kullanabilir ve analyzed alanı içinde bir not_analyzed alt alan olabilir (en bu örnekte item diyelim).

haritalama ile bu tür
{ 
    "yourtype": { 
    "properties": { 
     "item": { 
     "type": "string", 
     "fields": { 
      "raw": { 
      "type": "string", 
      "index": "not_analyzed" 
      } 
     } 
     } 
    } 
    } 
} 

, değerler Hamburgers ve Hamburger Buns her Birden çok alanda item ve item.raw göre analizör tarafından "inceledi" olduğunu kontrol edebilirsiniz: Sizin haritalama şuna benzer olurdu Hamburger için

:

curl -XGET 'localhost:9200/yourtypes/_analyze?field=item&pretty' -d 'Hamburger' 
{ 
    "tokens" : [ { 
    "token" : "hamburger", 
    "start_offset" : 0, 
    "end_offset" : 10, 
    "type" : "<ALPHANUM>", 
    "position" : 1 
    } ] 
} 
curl -XGET 'localhost:9200/yourtypes/_analyze?field=item.raw&pretty' -d 'Hamburger' 
{ 
    "tokens" : [ { 
    "token" : "Hamburger", 
    "start_offset" : 0, 
    "end_offset" : 10, 
    "type" : "word", 
    "position" : 1 
    } ] 
} 

Hamburger Buns için:

curl -XGET 'localhost:9200/yourtypes/_analyze?field=item&pretty' -d 'Hamburger Buns' 
{ 
    "tokens" : [ { 
    "token" : "hamburger", 
    "start_offset" : 0, 
    "end_offset" : 10, 
    "type" : "<ALPHANUM>", 
    "position" : 1 
    }, { 
    "token" : "buns", 
    "start_offset" : 11, 
    "end_offset" : 15, 
    "type" : "<ALPHANUM>", 
    "position" : 2 
    } ] 
} 
curl -XGET 'localhost:9200/yourtypes/_analyze?field=item.raw&pretty' -d 'Hamburger Buns' 
{ 
    "tokens" : [ { 
    "token" : "Hamburger Buns", 
    "start_offset" : 0, 
    "end_offset" : 15, 
    "type" : "word", 
    "position" : 1 
    } ] 
} 

Gördüğünüz gibi, not_analyzed alanı, tam olarak girildiği gibi el değmemiş olarak endekslenecek. Şimdi

, hadi endeks iki örnek belgeler bu göstermek için: nihayet

curl -XPOST localhost:9200/yourtypes/_bulk -d ' 
{"index": {"_type": "yourtype", "_id": 1}} 
{"item": "Hamburger"} 
{"index": {"_type": "yourtype", "_id": 2}} 
{"item": "Hamburger Buns"} 
' 

Ve sorunuzun cevabı, sen Hamburger üzerinde tam bir eşleşme yapmak istiyorsanız, size alt alanda item.raw içinde arama yapabilirsiniz

curl -XPOST localhost:9200/yourtypes/yourtype/_search -d '{ 
    "query": { 
    "term": { 
     "item.raw": "Hamburger" 
    } 
    } 
}' 

Ve alırsınız: böyle (açılan dava da maç için vardır unutmayın)

{ 
    ... 
    "hits" : { 
    "total" : 1, 
    "max_score" : 0.30685282, 
    "hits" : [ { 
     "_index" : "yourtypes", 
     "_type" : "yourtype", 
     "_id" : "1", 
     "_score" : 0.30685282, 
     "_source":{"item": "Hamburger"} 
    } ] 
    } 
} 

GÜNCELLEME (yorumlar/aşağıda tartışma ve soru yeniden düzenleme bakınız)

yorumlardan seni örnek alarak ve HaMbUrGeR BuNs maçı Hamburger buns sadece böyle bir match sorgusu ile elde edebiliriz yaşamak istiyor. Yukarıdaki Sen beklediğiniz olarak analizörü tutabilir

{ 
    ... 
    "hits" : { 
    "total" : 1, 
    "max_score" : 0.2712221, 
    "hits" : [ { 
     "_index" : "yourtypes", 
     "_type" : "yourtype", 
     "_id" : "2", 
     "_score" : 0.2712221, 
     "_source":{"item": "Hamburger Buns"} 
    } ] 
    } 
} 
+1

Hey, bu cevaba koyduğunuz zaman için teşekkürler, maalesef sorumu cevaplamıyor. Anlamıyorum ki, tam terimini not_analyzed alanında ararsam, doğru sonucu döndürecektir, ancak daha fazla esneklik arıyorum. Örneğin, "Not_analyzed" in yapamayacağı "HaMbUrGeRs BuN" araması yaparsam "Hamburger Çörekler" ini iade etmesini istiyorum. Bu, analiz edildikten sonra, eşleştikçe "kesin" sonuçtur. Bu mantıklı mı? – abroekhof

+0

Evet, bu mantıklı. Sorunuzu yanlış anlamış olursam özür dilerim. Bununla birlikte, sorunuzu güncellemeniz ve çok alanları bildiğinizden bahsetmelisiniz ve aradığınız şey bu değil. – Val

+0

Bitti - girişiniz için tekrar teşekkürler, minnettarım. – abroekhof

4

verecektir aynı iki endeksli dokümanlara dayanarak

curl -XPOST localhost:9200/yourtypes/yourtype/_search?pretty -d '{ 
    "query": { 
    "match": { 
     "item": { 
     "query": "HaMbUrGeR BuNs", 
     "operator": "and" 
     } 
    } 
    } 
}' 

(küçük harf, tokenize, kök, ...) ve aramak için artan sorgu olarak match_phrase ana sorgu olarak query_string kullanın. Böyle bir şey: Hem belgeleri maç olacak

{ 
    "bool" : { 
     "should" : [ 
     { 
      "query_string" : { 
       "default_field" : "your_field", 
       "default_operator" : "OR", 
       "phrase_slop" : 1, 
       "query" : "Hamburger" 
      } 
     }, 
     { 
      "match_phrase": { 
       "your_field": { 
        "query": "Hamburger" 
       } 
      } 
     } 
     ] 
    } 
} 

ve tam eşleme (match_phrase), sorgu maç beri üstünde hem should hükümler olması (ve daha yüksek puan almak)

default_operator OR ayarlandığında olacak Ayrıca "Hamburger Çörekler" sorgusu (hamburger VEYA bun maçı) "Hamburger" belgesine eşleşmesine yardımcı olacaktır. phrase_slop, 1 ile eşleşecek şekilde ayarlanır; Hamburger Buns için arama, belge Hamburger Big Buns ile eşleşmeyecektir. Bu isteğe bağlı olarak ayarlayabilirsiniz.

Daha fazla ayrıntı için Closer is better, Query string'a bakabilirsiniz.