一尘不染

跨字段搜索,每个字段中有多个完整和不完整的短语

elasticsearch

示例数据:

PUT /test/test/1
{
    "text1":"cats meow",
    "text2":"12345",
    "text3":"toy"
}

PUT /test/test/2
{
    "text1":"dog bark",
    "text2":"98765",
    "text3":"toy"
}

还有一个示例查询:

GET /test/test/_search
{
    "size": 25,
    "query": {
        "multi_match" : {
            "fields" : [
                "text1", 
                "text2",
                "text3"
            ],
            "query" : "meow cats toy",
            "type" : "cross_fields"
        }
    }
}

首先返回击中的猫,然后返回狗,这就是我想要的。

但是 当您查询时cat toy,猫和狗的相关性得分相同。我希望能够考虑到该单词的前缀(并且可能在该字段中添加了其他几个单词),然后运行cross_fields

因此,如果我搜索:

GET /test/test/_search
{
    "size": 25,
    "query": {
        "multi_match" : {
            "fields" : [
                "text1", 
                "text2",
                "text3"
            ],
            "query" : "cat toy",
            "type" : "phrase_prefix"
        }
    }
}

要么

GET /test/test/_search
{
    "size": 25,
    "query": {
        "multi_match" : {
            "fields" : [
                "text1", 
                "text2",
                "text3"
            ],
            "query" : "meow cats",
            "type" : "phrase_prefix"
        }
    }
}

我应该得到cat / ID 1,但没有。

我发现使用cross_fields可以实现多词短语,但不能实现多不完整的短语。并phrase_prefix获得不完整的短语,但不能获得多个不完整的短语…

筛选文档确实并没有帮助我发现如何结合这两者。


阅读 154

收藏
2020-06-22

共1个答案

一尘不染

是的,我必须使用分析仪…

添加任何数据之前,在创建索引时将分析器应用于这些字段。添加数据后,我找不到更简单的方法来执行此操作。

我发现的解决方案是将所有短语分解成每个单独的前缀,因此cross_fields可以做到这一点。您可以在edge-ngram
此处了解有关使用的更多信息。

因此,而不是cross_field只是搜索cats短语,它现在要搜索:ccacat,和cats和每句话后......所以text1场将看起来像这样弹性:c ca cat cats m me meo meow

~~~

以下是使上述问题示例起作用的步骤:

首先,您创建并命名分析器。要了解多一点什么过滤器的值的含义,我建议你看看这个

PUT /test
{
    "settings": {
        "number_of_shards": 1, 
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    }
}

然后,我将此分析仪附加到每个字段。我更改了,text1以匹配我将其应用到的字段。

PUT /test/_mapping/test
{
    "test": {
        "properties": {
            "text1": {
                "type":     "string",
                "analyzer": "autocomplete"
            }
        }
    }
}

我跑来GET /test/_mapping确保一切正常。

然后添加数据:

POST /test/test/_bulk
{ "index": { "_id": 1 }}
{ "text1": "cats meow", "text2": "12345", "text3": "toy" }
{ "index": { "_id": 2 }}
{ "text1": "dog bark", "text2": "98765", "text3": "toy" }

和搜索!

{
    "size": 25,
    "query": {
        "multi_match" : {
            "fields" : [
                "text1", 
                "text2",
                "text3"
            ],
            "query" : "cat toy",
            "type" : "cross_fields"
        }
    }
}

哪个返回:

{
   "took": 3,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": 0.70778143,
      "hits": [
         {
            "_index": "test",
            "_type": "test",
            "_id": "1",
            "_score": 0.70778143,
            "_source": {
               "text1": "cats meow",
               "text2": "12345",
               "text3": "toy"
            }
         },
         {
            "_index": "test",
            "_type": "test",
            "_id": "2",
            "_score": 0.1278426,
            "_source": {
               "text1": "dog bark",
               "text2": "98765",
               "text3": "toy"
            }
         }
      ]
   }
}

当您搜索时cat toy,这会在两者之间形成对比,而之前的分数是相同的。但是现在,这cat首热门歌曲的得分更高了。这是通过考虑每个词组的每个前缀(在这种情况下/短语中最多20个字符),然后查看数据与的相关性来实现的cross_fields

2020-06-22