我想要实现的是人们在没有语言意识的情况下搜索个人的能力,但不会惩罚那些人。我的意思是:
鉴于我建立索引:
我希望能够允许这样的转换:
所以如果有人搜索: QUERY |结果(我只包括ID,但它实际上是完整的记录)
从那开始我尝试创建索引分析器并过滤:
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "keyword",
"char_filter": [
"my_char_filter"
]
}
},
"char_filter": {
"my_char_filter": {
"type": "mapping",
"mappings": [
"ö => o",
"ö => oe"
]
}
}
}
}
}
但这是无效的,因为它试图映射到同一个角色。
我错过了什么?我需要多个分析仪吗?任何方向都会受到赞赏。
答案 0 :(得分:1)
由于自定义映射在您的情况下是不够的,如上面的显示注释,让我们使用您的数据和char规范化。
在您的情况下,由于ø和oe转换,使用unidecode
进行规范化是不够的。例如:
import unicodedata
def strip_accents(s):
return ''.join(
c for c in unicodedata.normalize('NFD', s)
if unicodedata.category(c) != 'Mn'
)
body_matches = [
u'Jorgensen',
u'Jörgensen',
u'Jørgensen',
u'Joergensen',
]
for b in body_matches:
print b,strip_accents(b)
>>>> Jorgensen Jorgensen
>>>> Jörgensen Jorgensen
>>>> Jørgensen Jørgensen
>>>> Joergensen Joergensen
所以,我们需要一个自定义翻译。到目前为止,我只设置了你展示的那些字符,但随时可以填写清单。
accented_letters = {
u'ö' : [u'o',u'oe'],
u'ø' : [u'o',u'oe'],
}
然后,我们可以对单词进行规范化并将它们存储在特殊属性body_normalized
中,并将它们作为Elasticsearch记录的字段编入索引。
插入后,您可以执行两种类型的搜索:
body
字段进行查询搜索,也未进行规范化。body_normalized
字段让我们看一个例子
body_matches = [
u'Jorgensen',
u'Jörgensen',
u'Jørgensen',
u'Joergensen',
]
print "------EXACT MATCH------"
for body_match in body_matches:
elasticsearch_query = {
"query": {
"match" : {
"body" : body_match
}
}
}
es_kwargs = {
"doc_type" : "your_type",
"index" : 'your_index',
"body" : elasticsearch_query
}
res = es.search(**es_kwargs)
print body_match," MATCHING BODIES=",res['hits']['total']
for r in res['hits']['hits']:
print "-",r['_source'].get('body','')
print "\n------SIMILAR MATCHES------"
for body_match in body_matches:
body_match = normalize_word(body_match)
elasticsearch_query = {
"query": {
"match" : {
"body_normalized" : body_match
}
}
}
es_kwargs = {
"doc_type" : "your_type",
"index" : 'your_index',
"body" : elasticsearch_query
}
res = es.search(**es_kwargs)
print body_match," MATCHING NORMALIZED BODIES=",res['hits']['total']
for r in res['hits']['hits']:
print "-",r['_source'].get('body','')
您可以在this notebook
中看到正在运行的示例答案 1 :(得分:0)
在玩了很多之后,到目前为止我想出了以下方法:
我们无法在一个字段中存储多个数据表示。这确实有意义,所以相反,就像它被建议一样,我们将它存储在像子字段这样的相同字段的多个表示中。我使用Kibana和/或Postman完成了所有操作。
使用以下设置创建索引:
PUT surname
{
"mappings": {
"individual": {
"_all": { "enabled": false },
"properties": {
"id": { "type": "integer" },
"name" : {
"type": "string",
"analyzer": "not_folded",
"fields": {
"double": {
"type": "string",
"analyzer": "double_folder"
},
"single": {
"type": "string",
"analyzer": "folded"
}
}
}
}
}
},
"settings": {
"number_of_shards": 1,
"analysis": {
"analyzer": {
"double_folder": {
"tokenizer": "icu_tokenizer",
"filter" : [
"icu_folding"
],
"char_filter": [
"my_char_filter"
]
},
"folded": {
"tokenizer": "icu_tokenizer",
"filter": [
"icu_folding"
]
},
"not_folded": {
"tokenizer": "icu_tokenizer",
"filter": [
"lowercase"
]
}
},
"char_filter": {
"my_char_filter": {
"type": "mapping",
"mappings": [
"ö => oe"
]
}
}
}
}
}
在这种情况下,它以3种不同的格式存储所有名称:
分片数量一个是测试的重要位,因为在没有足够数据的情况下,多个分片不能很好地工作。更多阅读Relevance is broken
然后我们可以将测试数据添加到我们的索引中:
POST surname/individual/_bulk
{ "index": { "_id": 1}}
{ "id": "1", "name": "Matt Jorgensen"}
{ "index": { "_id": 2}}
{ "id": "2", "name": "Matt Jörgensen"}
{ "index": { "_id": 3}}
{ "id": "3", "name": "Matt Jørgensen"}
{ "index": { "_id": 4}}
{ "id": "4", "name": "Matt Joergensen"}
剩下的就是测试我们是否得到了适当的回应:
GET surname/_search
{
"query": {
"multi_match": {
"type": "most_fields",
"query": "Jorgensen",
"fields": [ "name","name.double", "name.single" ]
}
}
}