【问题标题】:Elasticsearch in Python. How to get closes integer from searchPython 中的弹性搜索。如何从搜索中获取关闭整数
【发布时间】:2019-04-05 10:18:24
【问题描述】:

我在大型索引数据库上使用弹性搜索。其中一个查询需要找到一个整数值和一个字符串,例如:

s = Search(using=es, index="index1").extra(size=500) \
                        .query("match_phrase", name={"query": "john".casefold()})\
                        .query("match", age="46")

这将搜索包含“John white”和“46”的数据记录。但是,如果年龄不正确,我想获得一条包含“John white”和最接近“46”的年龄的记录(假设我有这些记录,否则它不会返回任何内容)。

然而,上面的查询只返回年龄正好“46”的记录。

类似的问题已经存在于 SO:how to find the nearest / closest number using Query DSL in elasticsearch

但我不确定如何将 JSON 合并到我的查询中,因为我使用的是特定的 python 模块。

一个典型的例子是我可以在字符串上使用模糊性。但我认为在弹性搜索中不可能以同样的方式对整数进行模糊处理。

【问题讨论】:

    标签: python json elasticsearch integer elasticsearch-dsl


    【解决方案1】:

    我建议使用基于脚本的排序来完成此操作,如下所述: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#_script_based_sorting

    假设您只匹配名字 - 如果您想完全匹配名称,我建议使用基于过滤器的匹配。我在索引中使用了三个不同的“用户”,定义如下:

    POST index1/_doc
    {
      "name": "John White",
      "age": 46
    }
    
    POST index1/_doc
    {
      "name": "John White",
      "age": 40
    }
    
    POST index1/_doc
    {
      "name": "John Black",
      "age": 47
    }
    

    我发现使用 Kibana 的开发工具进行测试,然后将其转换为 Python Elasticsearch DSL 兼容格式更容易编写像这样更复杂的东西 - 所以在 Kibana 中,我最终想出了以下内容:

    GET index1/_search
    {
      "query": {
        "match_phrase": {
          "name": {
            "query": "john"
          }
        }
      },
      "sort": {
        "_script": {
          "type": "number",
          "script": {
            "lang": "painless",
            "source": "Math.abs(doc['age'].value - params.target_age)",
            "params": {
              "target_age": 46
            }
          },
          "order": "asc"
        }
      }
    }
    

    注意,使用差异的绝对值将为您提供任一方向上最接近的值(即年轻或年长)。如果您的要求不同,可能需要进行一些调整。只需根据查询的变化调整参数以适应不同的目标年龄。

    一旦经过测试和验证,转换为 Python Elasticsearch DSL 就很容易了 - 您可以使用“自动缩进”功能来降低 sort 的复杂性并将其直接放入您现有的语句中。

    s = Search(using=es, index="index1").extra(size=500) \
        .query("match_phrase", name={"query": "john".casefold()}) \
        .sort({"_script":{"type":"number","script":{"lang":"painless","source": \
        "Math.abs(doc['age'].value - params.target_age)", \
        "params":{"target_age":46}},"order":"asc"}})
    

    执行此操作会返回预期的响应:

    <Response: [<Hit(index1/_doc/VR3e7WkBsHIsqLp6vfx_): {'name': 'John White', 'age': 46}>, <Hit(index1/_doc/Vx3f7WkBsHIsqLp6DPxM): {'name': 'John Black', 'age': 47}>, <Hit(index1/_doc/Vh3e7WkBsHIsqLp6yfxd): {'name': 'John White', 'age': 40}>]>
    

    但是,正如您所指出的,您想要 最接近 值,我建议将 size 参数更改为 1

    【讨论】:

    • 通过最接近的值,我的意思是如果查询想要“46”并且数据只包含“40”和“47”,它给我的第一个结果(因为它有最高分)将是“ 47"。例如,如果在您的查询中,目标年龄是“45”,那么搜索返回的最高分数是多少?我强调分数,因为对我来说,让最高分数成为最接近查询的年龄值很重要。仅仅对返回的响应进行排序是不够的。
    • @user7331538 示例查询仅侧重于查找最接近的年龄以及match_phrase 子句中提供的任何查询;不考虑实际的_score 值。所以要回答你的问题,使用我的查询,如果match_phrase 命中john,并且返回 2 个结果,年龄为 40 岁和 47 岁,目标年龄为 45 岁,则 47 的值将作为顶部返回结果。
    猜你喜欢
    • 2017-12-15
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    • 1970-01-01
    • 2017-12-02
    相关资源
    最近更新 更多