我有一个包含3个文档的索引。

            {
                    "firstname": "Anne",
                    "lastname": "Borg",
                }

            {
                    "firstname": "Leanne",
                    "lastname": "Ray"
                },

            {
                    "firstname": "Anne",
                    "middlename": "M",
                    "lastname": "Stone"
                }

当我搜索“Anne”时,我希望Elastic返回所有这3个文档(因为它们在一定程度上都与“Anne”相匹配)。但是,我希望Leanne Ray的得分(相关性排名)较低,因为搜索词“Anne”在该文档中的出现位置比在其他两个文档中出现的要晚。

最初,我使用的是ngram标记器。我的索引映射中还有一个生成的字段,称为“full_name”,其中包含名字,中间名和姓氏字符串。当我搜索“Anne”时,所有3个文档都在结果集中。但是,安妮·斯通(Anne M Stone)与莱安·雷(Leanne Ray)得分相同。安妮·斯通(Ann M Stone)的得分应该比莱安(Leanne)高。

为了解决这个问题,我将我的ngram标记器更改为edge_ngram标记器。这具有将Leanne Ray从结果集中完全删除的效果。我们希望将此结果保留在结果集中-因为它仍然包含查询字符串-但得分比其他两个更好的匹配要低。

我在某处读到,可能在同一索引中将边缘ngram过滤器与ngram过滤器一起使用。如果是这样,我应该如何重新创建索引呢?有更好的解决方案吗?

这是初始索引设置。
{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "filter": [
                        "lowercase"
                    ],
                    "type": "custom",
                    "tokenizer": "my_tokenizer"
                }
            },
            "tokenizer": {
                "my_tokenizer": {
                    "token_chars": [
                        "letter",
                        "digit",
                        "custom"
                    ],
                    "custom_token_chars": "'-",
                    "min_gram": "3",
                    "type": "ngram",
                    "max_gram": "4"
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "contact_id": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            },

            "firstname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },


            "lastname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "middlename": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "full_name": {
                "type": "text",
                "analyzer": "my_analyzer",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

这是我的查询
{
    "query": {
        "bool": {
            "should": [
                {
                    "query_string": {
                        "query": "Anne",
                        "fields": [
                            "full_name"
                        ]
                    }
                }
            ]
        }
    }
}

这带来了这些结果
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 0.59604377,
        "hits": [
            {
                "_index": "contacts_15",
                "_type": "_doc",
                "_id": "3",
                "_score": 0.59604377,
                "_source": {
                    "firstname": "Anne",
                    "lastname": "Borg"
                }
            },
            {
                "_index": "contacts_15",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.5592099,
                "_source": {
                    "firstname": "Anne",
                    "middlename": "M",
                    "lastname": "Stone"
                }
            },
            {
                "_index": "contacts_15",
                "_type": "_doc",
                "_id": "2",
                "_score": 0.5592099,
                "_source": {
                    "firstname": "Leanne",
                    "lastname": "Ray"
                }
            }
        ]
    }

如果我改用边缘ngram标记器,则索引的设置如下所示:
{
    "settings": {
        "max_ngram_diff": "10",
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "filter": [
                        "lowercase"
                    ],
                    "type": "custom",
                    "tokenizer": ["edge_ngram_tokenizer"]
                }
            },
            "tokenizer": {
                "edge_ngram_tokenizer": {
                    "token_chars": [
                        "letter",
                        "digit",
                        "custom"
                    ],
                    "custom_token_chars": "'-",
                    "min_gram": "2",
                    "type": "edge_ngram",
                    "max_gram": "10"
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "contact_id": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            },

            "firstname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },


            "lastname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "middlename": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "full_name": {
                "type": "text",
                "analyzer": "my_analyzer",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

而同一查询将带回此新结果集...
   "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.5131824,
        "hits": [
            {
                "_index": "contacts_16",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.5131824,
                "_source": {
                    "firstname": "Anne",
                    "middlename": "M",
                    "lastname": "Stone"
                }
            },
            {
                "_index": "contacts_16",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.4100108,
                "_source": {
                    "firstname": "Anne",
                    "lastname": "Borg"
                }
            }
        ]
    }

最佳答案

您可以继续使用ngram(即第一个解决方案),但随后您需要更改查询以提高相关性。它的工作方式是在multi_match子句中添加增强的should查询,以增加其名字或姓氏与输入完全匹配的文档的分数:

{
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "Anne",
            "fields": [
              "full_name"
            ]
          }
        }
      ],
      "should": [
        {
          "multi_match": {
            "query": "Anne",
            "fields": [
              "firstname",
              "lastname"
            ],
            "boost": 10
          }
        }
      ]
    }
  }
}

该查询将Anne BorgAnne M Stone带到Leanne Ray之前。

更新

这是我得出结果的方式。

首先,我使用创建了一个测试索引,与您添加到问题中的设置/映射完全相同:
PUT test
{ ... copy/pasted mappings/settings ... }

然后,我添加了您提供的三个示例文档:
POST test/_doc/_bulk
{"index":{}}
{"firstname":"Anne","lastname":"Borg"}
{"index":{}}
{"firstname":"Leanne","lastname":"Ray"}
{"index":{}}
{"firstname":"Anne","middlename":"M","lastname":"Stone"}

最后,如果您在上面运行我的查询,则会得到以下结果,这正是您期望的结果(看分数):
{
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 5.1328206,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "4ZqbDHIBhYuDqANwQ-ih",
        "_score" : 5.1328206,
        "_source" : {
          "firstname" : "Anne",
          "lastname" : "Borg"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "45qbDHIBhYuDqANwQ-ih",
        "_score" : 5.0862665,
        "_source" : {
          "firstname" : "Anne",
          "middlename" : "M",
          "lastname" : "Stone"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "4pqbDHIBhYuDqANwQ-ih",
        "_score" : 0.38623023,
        "_source" : {
          "firstname" : "Leanne",
          "lastname" : "Ray"
        }
      }
    ]
  }
}

关于elasticsearch - 如何在Elasticsearch索引中同时使用ngram和Edge ngram标记器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61747380/

10-10 21:20