Elasticsearch查询良好的标题关键字结果

Sim*_*sch 5 elasticsearch

我们有一个Elasticsearch索引,其中包含要按标题和描述搜索的产品目录。

我们希望它具有以下约束:

  • 我们正在搜索标题和描述中是否出现(标题中的匹配应比描述重要一倍)
  • 我们希望它具有非常模糊的搜索结果(但仍然是准确的结果)
  • 与搜索项不匹配的结果不应被滤除,而应在以后显示(因此,匹配结果应位于顶部,较差的结果应位于底部)
  • category_id应将产品过滤掉(因此不应显示其他类别的结果)
  • created_at属性在排序中的值也应很高。产品应得分“获得”的“较旧”。(这很重要,因为他们每天都在失去重要性)

我试图创建这样的查询,但结果确实不准确。有时会找到完全无关的东西。我认为这是由于通配符查询。

另外,我认为必须为“ created_at”评分提供一个更优雅的解决方案。对?

我正在使用Elasticsearch 6.2

这是我当前的代码。我很高兴看到一个优雅的解决方案:

{
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "min_score": 0.3,
  "size": 12,
  "from": 0,
  "query": {
    "bool": {
      "filter": {
        "terms": {
          "category_id": [
            "212",
            "213"
          ]
        }
      },
      "should": [
        {
          "match": {
            "title_completion": {
              "query": "Development",
              "boost": 20
            }
          }
        },
        {
          "wildcard": {
            "title": {
              "value": "*Development*",
              "boost": 1
            }
          }
        },
        {
          "wildcard": {
            "title_completion": {
              "value": "*Development*",
              "boost": 10
            }
          }
        },
        {
          "match": {
            "title": {
              "query": "Development",
              "operator": "and",
              "fuzziness": 1
            }
          }
        },
        {
          "range": {
            "created_at": {
              "gte": 1563264817998,
              "boost": 11
            }
          }
        },
        {
          "range": {
            "created_at": {
              "gte": 1563264040398,
              "boost": 4
            }
          }
        },
        {
          "range": {
            "created_at": {
              "gte": 1563256264398,
              "boost": 1
            }
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Pie*_*gel 2

首先,构建返回相关结果的请求通常是一项艰巨的任务。在不知道文件内容的情况下是无法完成的。也就是说,我可以给您提示来满足您的要求并避免不相关的结果。

我们正在搜索标题和描述中的事件(标题中的匹配应该是描述的两倍)

您可以像在查询中那样使用,boost与描述相比,标题匹配更加重要。

我们希望它有一个非常轻的模糊搜索结果(但仍然是准确的结果)

您应该使用AUTO模糊字段的值来根据术语的长度定义不同的模糊度值。例如,默认情况下,少于 3 个字母的术语(最常见的术语,其中字母的更改可能导致不同的单词)将不允许更改。超过 3 个字母的术语将允许进行 1 次更改,超过 5 个字母将允许进行 2 次更改。您可以根据您的测试更改此行为。

与搜索词不匹配的结果不应被过滤掉,而只能在稍后显示(因此匹配的结果应位于顶部,较差的结果应位于底部)

should在语句中使用子句bool。语句中的子句should不会过滤文档(除非另有说明)。子句中的查询should仅用于增加分数。

Category_id 应过滤掉产品(因此不应显示其他类别的结果)

在语句中使用mustoffilter子句bool可确保所有文档都验证约束。如果您不希望子查询对分数做出贡献(我相信这是您的情况),请使用filter而不是match因为filter将能够缓存结果。您的查询符合此要求。

在排序中,created_at 属性的值也应该非常高。产品越“老”,分数就应该越低。(这一点非常重要,因为它们每天都会失去重要性)

您应该使用function score带有衰减函数的a 。如果您不清楚衰减函数,您可以跳过文档中的方程并跳转到不言自明的图。以下查询是使用高斯衰减函数的示例。

{
    "function_score": {
        // Name of the decay function
        "gauss": {
            // Field to use
            "created_at": {
                    "origin": "now",  // "now" is the default so you can omit this field
                    "offset": "1d",   // Values with less than 1 day will not be impacted
                    "scale": "10d",   // Duration for which the scores will be scaled using a gauss function
                    "decay" : 0.01    // Score for values further than scale
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编写查询的提示

  • 避免通配符查询:如果使用*它们,效率不高,并且会消耗大量内存。如果您希望能够搜索术语的一部分(当用户搜索“house”时查找“penthouse”),您应该使用ngram分词器创建一个子字段,并使用该子字段编写一个标准match查询。

  • 避免设置最低分数:分数是一个相对值。小分或高分并不意味着该文档相关或不相关。您可以阅读这篇有关该主题的文章。

  • 小心fuzzy查询:模糊会产生大量噪音并使用户感到困惑。一般来说,我建议增加AUTO模糊的默认阈值,并接受某些拼写错误的查询不会返回良好的结果。通常,与理解为什么他有完全不相关的结果相比,用户检测输入中的拼写错误更容易。

查询示例

这只是一个示例,您需要根据您的数据进行调整。

{
  "size": 12,
  "query": {
    "bool": {
      "filter": {
        "terms": {
          "category_id": <CATEGORY_IDS>
        }
      },
      "should": [
        {
          "match": {
            "title": {
              "query": <QUERY>,
              "fuzziness": AUTO:4:12,
              "boost": 3
            }
          }
        },
        {
          "match": {
            "title_completion": {
              "query": <QUERY>,
              "boost": 1
            }
          }
        },
        {
          "match": {
            // title_completion field with ngram tokenizer
            "title_completion.ngram": {
              "query": <QUERY>,
              // Use lower boost because it match only partially
              "boost": 0.5
            }
          }
        }
      ]
    },
    "function_score": {
        // Name of the decay function
        "gauss": {
            // Field to use
            "created_at": {
                "origin": "now",  // "now" is the default so you can omit this field
                "offset": "1d",   // Values with less than 1 day will not be impacted
                "scale": "10d",   // Duration for which the scores will be scaled using a gauss function
                "decay" : 0.01    // Score for values further than scale
            }
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)