首页 > 解决方案 > 弹性的全文和 knn_vector 混合搜索

问题描述

我目前正在研究一个搜索引擎,并且我已经开始实现语义搜索。我使用弹性的开放发行版,我的映射目前看起来像这样:

{
  "settings": {
    "index": {
      "knn": true,
      "knn.space_type": "cosinesimil"
    }
  },
  "mappings": {
    "properties": {
      "title": { 
        "type" : "text"
      },
      "data": { 
        "type" : "text"
      },
      "title_embeddings": {
        "type": "knn_vector", 
        "dimension": 600
      },
      "data_embeddings": {
        "type": "knn_vector", 
        "dimension": 600
      }
    }
  }
}

对于基本的 knn_vector 搜索,我使用这个:

{
  "size": size,
  "query": {
    "script_score": {
      "query": {
        "match_all": { }
      },
      "script": {
        "source": "cosineSimilarity(params.query_value, doc[params.field1]) + cosineSimilarity(params.query_value, doc[params.field2])",
        "params": {
          "field1": "title_embeddings",
          "field2": "data_embeddings",
          "query_value": query_vec
        }
      }
    }
  }
}

我已经设法通过以下方式获得了一种混合搜索:

{
  "size": size,
  "query": {
    "function_score": {
      "query": {
        "multi_match": { 
          "query": query,
          "fields": ["data", "title"]
        }
      },
      "script_score": {
        "script": {
          "source": "cosineSimilarity(params.query_value, doc[params.field1]) + cosineSimilarity(params.query_value, doc[params.field2])",
          "params": {
            "field1": "title_embeddings",
            "field2": "data_embeddings",
            "query_value": query_vec
          }
        }
      }
    }
  }
}

问题是如果我在文档中没有这个词,那么它就不会被返回。例如,在第一个搜索查询中,当我搜索 trump(不在我的数据集中)时,我设法获取有关社交网络和政治的文档。混合搜索没有这些结果。

我试过这个:

 {
  "size": size,
  "query": {
    "function_score": {
      "query": {
        "match_all": { }
      },
      "functions": [
      {
        "filter" : {
          "multi_match": { 
            "query": query,
            "fields": ["data", "title"]
          }
        },
        "weight": 1
      },
      {
        "script_score" : {
          "script" : {
            "source": "cosineSimilarity(params.query_value, doc[params.field1]) + cosineSimilarity(params.query_value, doc[params.field2])",
            "params": {
              "field1": "title_embeddings",
              "field2": "data_embeddings",
              "query_value": query_vec
            }
          }
        },
        "weight": 4
      }
      ],
      "score_mode": "sum",
      "boost_mode": "sum"
    }
  }
}

但是多重匹配部分给所有匹配的文档一个恒定的分数,我想使用过滤器对我的文档进行排名,就像在正常的全文查询中一样。有什么想法吗?还是我应该使用其他策略?先感谢您。

标签: elasticsearchfull-text-searchembeddinghybrid

解决方案


在 Archit Saxena 的帮助下,我的问题得到了解决:

{
  "size": size,
  "query": {
    "function_score": {
      "query": {
        "bool": { 
          "should" : [
            {
              "multi_match" : { 
                "query": query,
                "fields": ["data", "title"]
              }
            },
            {
              "match_all": { }
            }
          ],
          "minimum_should_match" : 0
        }
      },
      "functions": [
      {
        "script_score" : {
          "script" : {
            "source": "cosineSimilarity(params.query_value, doc[params.field1]) + cosineSimilarity(params.query_value, doc[params.field2])",
            "params": {
              "field1": "title_embeddings",
              "field2": "data_embeddings",
              "query_value": query_vec
            }
          }
        },
        "weight": 20
      }
      ],
      "score_mode": "sum",
      "boost_mode": "sum"
    }
  }
}

推荐阅读