在实体查询中,我感兴趣是最匹配的项,而不是说最匹配的属性,这个在Most_fileds 或者best_fields都是以属性为中心的查询。
问题1:在多个属性中匹配同样的单词
考虑most_fields查询是怎么执行的:ElasticSearch对每一个属性生成一个match query 然后把这些query 包括在bool query 中。
我们用validate-query API看一下
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "Poland Street W1V",
"type": "most_fields",
"fields": [ "street", "city", "country", "postcode" ]
}
}
}
你可以看到一个文档匹配一个单词poland在两个属性中的相关度分值score会高于一个文档在一个属性匹配pland和street两个单词。
问题2:修剪长尾巴
我们可以用and 操作 和 minimum_should_match 参数去修剪一个很长的且不太相关的查询结果。可能我们可以这样:
{
"query": {
"multi_match": {
"query": "Poland Street W1V",
"type": "most_fields",
"operator": "and",
"fields": [ "street", "city", "country", "postcode" ]
}
}
}
也就是说,用and operator 意味着单词必须存在于同样的属性中,这样是绝对错误的,不满足我们的需求。
问题3:Term Frequencies
我们讨论缺省的相似度算法去计算相关度:tf/idf
Term Frequency
越多的term出现在一个文档中,则意味着越大的相关度
Inverse document frequency
越多的term出现在某个field 在全部的文档中,则越少的相关度
当我们搜索多个field时,tf/idf会带来一些惊喜的结果
例如当我们搜索“peter smith”,用first_name和last_name peter 是一个很常用的first name 而且 simith也是很常用的last name, 两周都会有很低的idfs. 但是要是我们有个人他的整个名字是 Smith Willianms? Smith 作为 first name 是非常不常见的,并且会有很高的 IDF。
一个简单访问,peter smith, 因为 smith在 first_name 这个属性上有很高的IDF,所以 在first name很高的IDF 会吞没掉 低的IDF peter as first name 和 smith as last name
Solution
这些问题存在是因为我们同事处理多个属性。如果我们将所有的属性合成到一个属性里面,这样的问题就解决了。例如,在上边的例子中,我们创建个属性叫full_name
{
"first_name": "Peter",
"last_name": "Smith",
"full_name": "Peter Smith"
}
当我们仅仅访问full_name
- 匹配更多的单词会胜过仅仅匹配重复的单词
- minimum_should_match 和operator parameters 可以用了
- first name 和 last name 的IDF 会联合到一起。所以不管smith 是first name 还是 last name 都没区别的
当这样的算法运行的时候,我们不希望存储冗余的数据。ElasticSearch 给我们提供了两个解决方案:
one at index time
one at search time
(这两个东西啊还不太懂, 之后会讲到)