首页 > 解决方案 > Elasticsearch 混合查询 - 始终返回 0 分

问题描述

我目前正在尝试对两个索引进行混合搜索:全文索引和 knn_vector(词嵌入)索引。目前,来自 Wikipedia 的超过 10,000 个文档在 ES 堆栈上被索引,并在这两个字段上都被索引(参见映射:“内容”、“嵌入”)。查询是众所周知的 n-gram (1,2,3),应该会产生结果(单词取自被索引的维基百科页面)。

同样重要的是要注意 knn_vector 索引被定义为嵌套对象。

这是索引项目的当前映射

mapping = {
        "settings": {
            "index": {
                "knn": True,
                "knn.space_type": "cosinesimil"
            }
        },
       "mappings": {
        "dynamic": 'strict', 
        "properties": {
            "elasticId": 
                { 'type': 'text' },
            "owners": 
                { 'type': 'text' },
            "type": 
                { 'type': 'keyword' },
            "accessLink": 
                { 'type': 'keyword' },
            "content": 
                { 'type': 'text'}, 
    "embeddings": {
                'type': 'nested', 
                "properties": {
                  "vector": {
                    "type": "knn_vector", 
                    "dimension": VECTOR_DIM, 
                          },
                    },
    },
}

我的目标是比较两个索引上的查询分数,以了解一个是否比另一个更有效(全文与 knn_vectors),以及弹性如何根据每个索引的分数选择返回对象。

我知道我可以简单地拆分查询(两个单独的查询),但理想情况下,我们可能希望在生产中使用这种类型的混合搜索。

这是同时搜索全文和 knn_vectors的当前查询:

def MakeHybridSearch(query):
    query_vector = convert_to_embeddings(query)
    result = elastic.search({
        "explain": True, 
        "profile": True, 
        "size": 2,
        "query": {
        "function_score": { #function_score
        "functions": [
            {
          "filter": { 
              "match": { 
                  "text": {
                      "query": query,
                      'boost': "5",  
                      }, 
                    }, 
                  },
            "weight": 2
          },
          {
          "filter": { 
              'script': {
                'source': 'knn_score',
                'params': {
                  'field': 'doc_vector',
                  'vector': query_vector,
                  'space_type': "l2"
                      }
                  }
                  },
                  "weight": 4
              }
          ],
          "max_boost": 5,
          "score_mode": "replace",
          "boost_mode": "multiply",
          "min_score": 5
          }
        }
      }, index='files_en', size=1000)

 

当前的问题是所有查询都没有返回任何内容。 结果

{
"took": 3,
"timed_out": false,
"_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
},
"hits": {
    "total": {
        "value": 0,
        "relation": "eq"
    },
    "max_score": null,
    "hits": []
},

即使查询确实返回了响应,它也会返回得分为 0 (score =0) 的命中。

查询结构是否有错误?这可能是在映射方面吗?如果没有,有没有更好的方法来做到这一点?

谢谢您的帮助 !

标签: pythonelasticsearch

解决方案


现在,aws elasticsearch 支持后过滤。

https://docs.aws.amazon.com/opensearch-service/latest/developerguide/knn.html

页面中的示例查询是

{
    "size": 2,
    "query": {
        "knn": {
            "my_vector2": {"vector": [2, 3, 5, 6], "k": 2}
        }
    },
    "post_filter": {
        "range": {
            "price": {"gte": 6, "lte": 10}
        }
    }
}

aws elasticsearch 还支持使用“script_score”进行预过滤(但它与原始 elasticsearch 中的“script_score”不同)

https://opendistro.github.io/for-elasticsearch-docs/docs/knn/knn-score-script/

页面中的示例查询是

{
    "size": 2,
    "query": {
        "script_score": {
            "query": {
                "bool": {
                    "filter": {
                        "term": {
                            "color": "BLUE"
                        }
                    }
                }
            },
            "script": {
                "lang": "knn",
                "source": "knn_score",
                "params": {
                    "field": "my_binary",
                    "query_value": "U29tZXRoaW5nIEltIGxvb2tpbmcgZm9y",
                    "space_type": "hammingbit"
                }
            }
        }
    }
}

推荐阅读