您在粘贴的内容中存在以下问题:
1)映射不正确
创建索引时,您指定了:
"mappings": {
"files": {
但是你的类型实际上是file
,而不是files
。如果你检查了映射,你会立即看到:
curl -XGET 'http://127.0.0.1:9200/files/_mapping?pretty=1'
2) 分析器定义错误
您已经指定了lowercase
分词器,但它会删除除字母以外的任何字符,(请参见文档),因此您的数字将被完全删除。
您可以使用分析 API来检查这一点:
curl -XGET 'http://127.0.0.1:9200/_analyze?pretty=1&text=My_file_2012.01.13.doc&tokenizer=lowercase'
3) 在搜索中使用Ngrams
在索引分析器和搜索分析器中都应包含ngram分词器。对于索引分析器,这是可以接受的,因为您希望ngrams被索引。但是,在搜索时,您希望搜索完整字符串,而不是每个ngram。
例如,如果您使用长度为1到4的ngrams索引"abcd"
,则将得到以下标记:
a b c d ab bc cd abc bcd
但是,如果您在搜索中使用"dcba"
(本不应匹配),并且您还使用ngrams分析搜索词,则实际上正在搜索以下内容:
d c b a dc cb ba dbc cba
因此,a
、b
、c
和 d
将匹配!
解决方案
首先,您需要选择正确的分析器。您的用户可能会搜索单词、数字或日期,但他们可能不希望 ile
匹配 file
。相反,使用edge ngrams可能更有用,它会将ngram锚定到每个单词的开头(或结尾)。
另外,为什么要排除docx
等格式?用户很可能想要搜索文件类型呢?
因此,让我们通过删除任何不是字母或数字的内容(使用pattern tokenizer)来将每个文件名拆分成较小的标记:
My_first_file_2012.01.13.doc
=> my first file 2012 01 13 doc
然后对于索引分析器,我们也会在每个令牌上使用边缘ngrams:
my => m my
first => f fi fir firs first
file => f fi fil file
2012 => 2 20 201 201
01 => 0 01
13 => 1 13
doc => d do doc
我们按照以下方式创建索引:
curl -XPUT 'http:
{
"settings" : {
"analysis" : {
"analyzer" : {
"filename_search" : {
"tokenizer" : "filename",
"filter" : ["lowercase"]
},
"filename_index" : {
"tokenizer" : "filename",
"filter" : ["lowercase","edge_ngram"]
}
},
"tokenizer" : {
"filename" : {
"pattern" : "[^\\p{L}\\d]+",
"type" : "pattern"
}
},
"filter" : {
"edge_ngram" : {
"side" : "front",
"max_gram" : 20,
"min_gram" : 1,
"type" : "edgeNGram"
}
}
}
},
"mappings" : {
"file" : {
"properties" : {
"filename" : {
"type" : "string",
"search_analyzer" : "filename_search",
"index_analyzer" : "filename_index"
}
}
}
}
}
'
现在,测试我们的分析器是否正常工作:
filename_search:
curl -XGET 'http://127.0.0.1:9200/files/_analyze?pretty=1&text=My_first_file_2012.01.13.doc&analyzer=filename_search'
[results snipped]
"token" : "my"
"token" : "first"
"token" : "file"
"token" : "2012"
"token" : "01"
"token" : "13"
"token" : "doc"
文件名索引:
curl -XGET 'http://127.0.0.1:9200/files/_analyze?pretty=1&text=My_first_file_2012.01.13.doc&analyzer=filename_index'
"token" : "m"
"token" : "my"
"token" : "f"
"token" : "fi"
"token" : "fir"
"token" : "firs"
"token" : "first"
"token" : "f"
"token" : "fi"
"token" : "fil"
"token" : "file"
"token" : "2"
"token" : "20"
"token" : "201"
"token" : "2012"
"token" : "0"
"token" : "01"
"token" : "1"
"token" : "13"
"token" : "d"
"token" : "do"
"token" : "doc"
OK - 看起来运行正常。因此,让我们添加一些文档:
curl -X POST "http://localhost:9200/files/file" -d '{ "filename" : "My_first_file_created_at_2012.01.13.doc" }'
curl -X POST "http://localhost:9200/files/file" -d '{ "filename" : "My_second_file_created_at_2012.01.13.pdf" }'
curl -X POST "http://localhost:9200/files/file" -d '{ "filename" : "Another file.txt" }'
curl -X POST "http://localhost:9200/files/file" -d '{ "filename" : "And_again_another_file.docx" }'
curl -X POST "http://localhost:9200/files/file" -d '{ "filename" : "foo.bar.txt" }'
curl -X POST "http://localhost:9200/files/_refresh"
尝试搜索:
curl -XGET 'http://127.0.0.1:9200/files/file/_search?pretty=1' -d '
{
"query" : {
"text" : {
"filename" : "2012.01"
}
}
}
'
成功!
#### 更新 ####
我意识到搜索2012.01
会匹配2012.01.12
和2012.12.01
,因此我尝试更改查询以使用文本短语查询。然而,这并没有起作用。原来,边缘ngram过滤器对于每个ngram都增加了位置计数(而我原本认为每个ngram的位置与单词开头的位置相同)。
上述第(3)点提到的问题仅在使用query_string
、field
或text
查询尝试匹配任何标记时才存在。但是,对于text_phrase
查询,它尝试按正确顺序匹配所有标记。
为了说明这个问题,请索引另一个具有不同日期的文档:
curl -X POST "http://localhost:9200/files/file" -d '{ "filename" : "My_third_file_created_at_2012.12.01.doc" }'
curl -X POST "http://localhost:9200/files/_refresh"
执行与上面相同的搜索:
curl -XGET 'http://127.0.0.1:9200/files/file/_search?pretty=1' -d '
{
"query" : {
"text" : {
"filename" : {
"query" : "2012.01"
}
}
}
}
'
第一个结果的日期是2012.12.01
,不是最佳匹配项2012.01
。因此,为了只匹配该确切短语,我们可以这样做:
curl -XGET 'http://127.0.0.1:9200/files/file/_search?pretty=1' -d '
{
"query" : {
"text_phrase" : {
"filename" : {
"query" : "2012.01",
"analyzer" : "filename_index"
}
}
}
}
'
或者,如果您仍然想匹配所有3个文件(因为用户可能记得文件名中的某些单词,但是顺序错误),那么您可以运行两个查询,但增加正确顺序的文件名的重要性:
curl -XGET 'http://127.0.0.1:9200/files/file/_search?pretty=1' -d '
{
"query" : {
"bool" : {
"should" : [
{
"text_phrase" : {
"filename" : {
"boost" : 2,
"query" : "2012.01",
"analyzer" : "filename_index"
}
}
},
{
"text" : {
"filename" : "2012.01"
}
}
]
}
}
}
'
p{L}
是什么)。我正在使用match
查询,我遇到的问题是,当我仅在文件名字段中搜索时,似乎可以工作,但在使用_all
时却不能:(。有什么想法吗? - Aldo 'xoen' Giambelluca"type": "query_parsing_exception", "reason": "No query registered for [text]",
还有其他人遇到过这个错误吗? - ASN