是否可以使用高于重复结果的唯一结果对span_near查询进行排名?

时间:2013-12-06 21:47:28

标签: elasticsearch

假设我有两个文件,其中包含“catField”,其中包含以下信息:

文件一:

happy cat
sad cat
meh cat

文件二:

happy cat
happy cat
happy cat

我正在尝试编写满足两个要求的查询:

  1. 找到长度至少为3的单词,后跟单词“cat”。
  2. 查询还应该将具有更多独特类型的猫(文档一)的文档排序为高于具有相同类型的猫(文档二)的文档。
  3. 这是我的初始解决方案,它使用span_near和regexp来满足第一个要求:

    "span_near": {
       "clauses": [
           {
                "span_multi": { 
                    "match": { 
                        "regexp": {
                            "catField": "[a-z]{3,}"
                        }
                    }
                }
            },
            {
                "span_multi": { 
                    "match": { 
                        "regexp": {
                            "catField": "cat"
                        }
                    }
                }
            }
       ],
       "slop": 0,
       "in_order": true
    }
    

    这对于查找带有猫列表的文档非常有用,但它会对文档1和文档2(上面)进行排序。如何才能满足将独特猫咪列表排名高于非独特猫咪列表的第二个要求?

1 个答案:

答案 0 :(得分:2)

所以这是一种使用一些索引魔法来获得你想要的东西的方法。我不完全确定你的要求(因为你可能正在使用比“快乐猫”更复杂的数据),但它应该让你从索引时间方向开始。

这可能是也可能不是您的设置的正确方法。根据索引大小和查询负载,短语查询/跨度查询/布尔组合可能会更好地工作。但是,您的要求很棘手,因为它们取决于订单,先前令牌的大小和变化的数量。

这样做的好处是,您的大部分复杂逻辑都会被编入索引,从而在查询时获得速度。但它确实会使您的数据更加严格。

curl -XDELETE localhost:9200/cats
curl -XPUT localhost:9200/cats -d '
{
    "settings" : {
        "number_of_shards" : 1,
        "number_of_replicas" : 0,
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "catalyzer" : {
                        "type" : "custom",
                        "tokenizer" : "keyword",
                        "filter" : ["cat_pattern", "unique", "cat_replace"]
                    }   
                },
                "filter" : {
                    "cat_pattern" : {
                     "type" : "pattern_capture",
                       "preserve_original" : false,
                       "patterns" : [
                          "([a-z]{3,} cat)"
                       ]   
                    },
                    "cat_replace" : {
                     "type" : "pattern_replace",
                       "preserve_original" : false,
                       "pattern" : "([a-z]{3,} cat)",
                       "replacement" : "cat"
                    }
                }
            }
        }
    },
    "mappings" : {
        "cats" : {
            "properties" : {
                "catField" : { 
                    "type" : "multi_field",
                    "fields": {
                        "catField" : {
                            "type": "string",
                            "analyzer": "standard"
                        },
                        "catalyzed" : {
                            "type": "string",
                            "index_analyzer": "catalyzer",
                            "search_analyzer" : "whitespace"
                        }
                    }
                }
            }
        }
    }
}'

首先,我们使用一系列自定义分析创建索引。首先,我们使用关键字分析器(实际上不进行标记,只发出一个令牌)进行标记。然后我们使用pattern_capture过滤器来查找前面有一个长于三个字符的单词的所有“猫”。然后我们使用unique过滤器来删除重复项(例如连续三次“快乐猫”)。最后,我们使用pattern_replace将“快乐猫”改为“猫”。

一个字段的最终标记只是“猫”,但如果有多种类型的猫,会出现更多的“猫”。

在搜索时,我们可以简单地搜索“猫”,而更经常提到“猫”的文档会提升得更高。由于我们的分析,更多提及意味着更多独特类型,因此我们“免费”获得提升行为。

我使用了多字段,因此您仍然可以查询原始字段(例如,如果您要搜索“快乐猫”)。

使用上述映射进行演示:

curl -XPOST localhost:9200/cats/cats/1 -d '
{
    "catField" : ["sad cat", "happy cat", "meh cat"]
}'

curl -XPOST localhost:9200/cats/cats/2 -d '
{
    "catField" : ["happy cat", "happy cat", "happy cat"]
}'

curl -XPOST localhost:9200/cats/cats/3 -d '
{
    "catField" : ["a cat", "x cat", "y cat"]
}'

curl -XPOST localhost:9200/cats/cats/_search -d '
{
    "query" : {
        "match": {
           "catField.catalyzed": "cat"
        }   
    }
}'

请注意,搜索不会返回第三个文档,因为它没有一个长度超过三个字符的cat。