Elasticsearch按参数查询和排序

时间:2018-06-01 13:41:47

标签: elasticsearch

如何通过elasticsearch

中的以下参数查询和排序文本

1 - 搜索查询在结果的第一部分中是准确的

2 - 搜索查询在结果的另一部分中是准确的

3 - 结果包含搜索查询的所有单词

例如:

我搜索时:i love dogs

结果必须分别为:

1-  I love dogs

2 - i love dogs and birds

3 - birds good but i love dogs and horses 

4 - Horses and i love dogs

5 - I love horses and dogs

6 - good dogs and i love horses

2 个答案:

答案 0 :(得分:2)

可以实现所需的行为,但需要对映射和查询进行一些调整。

为简短起见,这里是工作查询

首先,这是映射:

PUT my_phrase_search
{
  "mappings": {
    "doc": {
      "properties": {
        "expected_position": {
          "type": "long"
        },
        "my_phrase": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256,
              "normalizer": "my_normalizer"
            }
          }
        }
      }
    }
  },
  "settings": {
    "index": {
      "analysis": {
        "normalizer": {
          "my_normalizer": {
            "filter": [
              "lowercase"
            ],
            "type": "custom"
          }
        }
      }
    }
  }
}

注意:我添加了字段expected_position,以便更轻松地评估结果。

现在,查询:

POST my_phrase_search/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "should": [
              {
                "prefix": {
                  "my_phrase.keyword": "i love dogs"
                }
              }
            ],
            "_name": "prefix",
            "boost": 2
          }
        },
        {
          "bool": {
            "should": [
              {
                "match": {
                  "my_phrase": "i love dogs"
                }
              }
            ],
            "_name": "match"
          }
        },
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "my_phrase": "i love dogs"
                }
              }
            ],
            "_name": "phrase",
            "boost": 2
          }
        }
      ]
    }
  }
}

这给出了以下结果:

[
  {
    "_score": 4.015718,
    "_source": {
      "my_phrase": "I love dogs",
      "expected_position": 1
    },
    "matched_queries": [
      "match",
      "phrase",
      "prefix"
    ]
  },
  {
    "_score": 3.233316,
    "_source": {
      "my_phrase": "i love dogs and birds",
      "expected_position": 2
    },
    "matched_queries": [
      "match",
      "phrase",
      "prefix"
    ]
  },
  {
    "_score": 1.3836111,
    "_source": {
      "my_phrase": "birds good but i love dogs and horses ",
      "expected_position": 3
    },
    "matched_queries": [
      "match",
      "phrase"
    ]
  },
  {
    "_score": 1.2333161,
    "_source": {
      "my_phrase": "Horses and i love dogs",
      "expected_position": 4
    },
    "matched_queries": [
      "match",
      "phrase"
    ]
  },
  {
    "_score": 0.8630463,
    "_source": {
      "my_phrase": "I love horses and dogs",
      "expected_position": 5
    },
    "matched_queries": [
      "match"
    ]
  },
  {
    "_score": 0.38110584,
    "_source": {
      "my_phrase": "good dogs and i love horses",
      "expected_position": 6
    },
    "matched_queries": [
      "match"
    ]
  }
]

您可能想知道,它是如何运作的?这些变化都是必要的吗?让我们找出答案。

如果我们只使用text字段和match查询?

,该怎么办?

match查询如下所示:

POST my_phrase/doc/_search
{
  "query": {
    "match": {
      "my_phrase": "i love dogs"
    }
  }
}

这将为我们提供以下结果顺序:5 - 1 - 3 - 2 - 4 - 6

问题是,为什么查询"i love dogs"没有返回完美匹配1- I love dogs,作为第一个结果?为什么5 - I love horses and dogs先出现?

在这种情况下,答案是avgFieldLength,用于计算score,它是computed per shard,因此对于不同的文档可能略有不同。

很明显ES应该给我们从查询开始的结果。我们如何告诉ES更喜欢这些文件?

prefix字段

上添加keyword搜索

我们可以使用prefix查询与match查询联合bool查询(在这种情况下可以大致解释为OR),如下所示:

POST my_phrase/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "prefix": {
            "my_phrase.keyword": "i love dogs"
          }
        },
        {
          "match": {
            "my_phrase": "i love dogs"
          }
        }
      ]
    }
  }
}

请注意,prefix查询仅适用于keyword类型,因为它需要将文档解释为一个大标记。

此查询为我们提供了以下结果顺序:2 - 5 - 1 - 3 - 4 - 6

2跳了起来,但1没有。为什么会这样?

以下是角色的情况:keyword数据类型未经过分析,因此iI会对此前缀搜索产生影响。

我们如何才能使keyword不区分大小写?

使keyword案例内容

这是通过在映射中定义normalizer来实现的:

PUT my_phrase2
{
  "settings": {
    "analysis": {
      "normalizer": {
        "my_normalizer": {
          "type": "custom",
          "char_filter": [],
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "doc": {
      "properties": {
        "my_phrase": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256,
                "normalizer": "my_normalizer"
              }
            }
          }
      }
    }
  }
}

现在,相同的查询将为我们提供以下顺序:1 - 2 - 5 - 3 - 4 - 6

这已经相当不错了,但5 - I love horses and dogs仍然过高 - 高于3 - birds good but i love dogs and horses且匹配完全匹配。

match查询不关心短语中单词的顺序。我们可以提升具有正确顺序的文档吗?

添加match_phrase以提升词组匹配

match_phrase查询确实支持原始订单中的令牌。让我们在查询中使用它:

POST my_phrase2/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "prefix": {
            "my_phrase.keyword": "i love dogs"
          }
        },
        {
          "match_phrase": {
            "my_phrase": "i love dogs"
          }
        },
        {
          "match": {
            "my_phrase": "i love dogs"
          }
        }
      ]
    }
  }
}

这为我们提供了以下顺序:1 - 2 - 3 - 5 - 4 - 6

突然出现了!但5 - I love horses and dogs仍然高于4 - Horses and i love dogs。看起来短语匹配应该有利于4。

查询变得非常复杂,让我们找出文件实际匹配的部分。

为查询添加名称

可以为查询提供names,以便了解复杂问题的哪些部分实际生效:

POST my_phrase2/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "should": [
              {
                "prefix": {
                  "my_phrase.keyword": "i love dogs"
                }
              }
            ],
            "_name": "prefix"
          }
        },
...

感兴趣的文件的回复将给我们:

  {
    "_score": 0.8630463,
    "_source": {
      "my_phrase": "I love horses and dogs",
      "expected_position": 5
    },
    "matched_queries": [
      "match"
    ]
  },
  {
    "_score": 0.82221067,
    "_source": {
      "my_phrase": "Horses and i love dogs",
      "expected_position": 4
    },
    "matched_queries": [
      "match",
      "phrase"
    ]
  },

Doc 5与phrase部分不匹配。看起来得分波动再次打击了我们。

短语查询看起来更相关,有没有办法提升它?

最后:提升短语和前缀查询

有一种方法可以影响得分的计算,告诉ES查询的某些部分更重要,称为boost。以下是它的外观:

POST my_phrase2/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "should": [
              {
                "prefix": {
                  "my_phrase.keyword": "i love dogs"
                }
              }
            ],
            "_name": "prefix",
            "boost": 2
          }
        },
        {
          "bool": {
            "should": [
              {
                "match": {
                  "my_phrase": "i love dogs"
                }
              }
            ],
            "_name": "match"
          }
        },
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "my_phrase": "i love dogs"
                }
              }
            ],
            "_name": "phrase",
            "boost": 2
          }
        }
      ]
    }
  }
}

这个为我们提供了所需的结果顺序:1 - 2 - 3 - 4 - 5 - 6

请注意,我们还提升了prefix查询,因为我们希望降低match的重要性。

这种方法是安全的,还是过度拟合警告

尽管此查询完成了这项工作,但您可能希望执行大量的实际验证并进一步调整以确保足够的搜索结果。

完全符合这6个文档的查询可能不适合大型真实世界的集合,请将此答案作为优化的开始。

正如您所看到的,查询的所有部分都不是必需的:查询的名称可以很容易地省略,但在理解文档的匹配方式方面可以起到很好的帮助。

希望有所帮助!

答案 1 :(得分:0)

要获得所需的结果,您需要使用match_phrase_prefix参数,例如max_expansions示例,以便进一步阅读。

match_phrase_prefix

GET /_search
{
    "query": {
        "match_phrase_prefix" : {
            "message" : "quick brown f"
        }
    }
}