首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >混合搜索的最佳实践

混合搜索的最佳实践

原创
作者头像
点火三周
发布2025-01-04 19:13:55
发布2025-01-04 19:13:55
4711
举报
文章被收录于专栏:Elastic Stack专栏Elastic Stack专栏

在本文中,我们将通过例子探讨混合搜索,并展示它在与单独使用词法搜索或语义搜索技术相比时的优势。

什么是混合搜索?

混合搜索是一种结合了不同搜索方法的技术,如传统的词法术语匹配和语义搜索

当用户知道确切的词汇时,词法搜索表现出色。这种方法会找到相关的文档,并使用TF-IDF对它们进行合理排序。TF-IDF的意思是:在数据集中越常见的词对评分的贡献越小,而在某个特定文档中越常见的词对评分的贡献越大。

但是,如果查询中的词汇在文档中不存在呢?有时用户寻找的不是具体的内容,而是一个概念。例如,他们可能不是在找特定的餐馆,而是“一个适合家庭聚餐的好地方”。对于这种查询,语义搜索非常有用,因为它会考虑搜索查询的上下文,并带回类似的文档。不过,这种方法在处理数字时的精确度较低。

混合搜索通过结合词语匹配的精确度和语义搜索的上下文感知能力,为我们提供了两者的优点。

你可以在这篇文章中深入了解混合搜索,并在这篇文章中了解词法搜索和语义搜索的区别。

下面我们用房地产单位创建一个示例。

混合搜索查询示例
混合搜索查询示例

查询将是:Pinewood 2室 安静的地方,其中 安静的地方 (quiet home) 是查询的语义部分,而 Pinewood 2室 是文本或词法部分。

配置 ELSER

我们将使用 ELSER 作为我们的模型提供者。

首先创建推理端点:

代码语言:javascript
复制
PUT _inference/sparse_embedding/my-elser-model 
{
  "service": "elser",
  "service_settings": {
    "num_allocations": 1,
    "num_threads": 1
  }
}

如果这是你第一次使用 ELSER,可能会遇到 502 Bad Gateway 错误,因为模型正在后台加载。你可以在 Kibana 的 Machine Learning > Trained Models 中检查模型的状态。部署完成后,可以继续下一步。

检查训练模型
检查训练模型

配置索引

对于索引,我们将使用文本字段和用于语义字段的 semantic_text。我们将复制描述字段,因为我们希望同时用于 matchsemantic 查询。

代码语言:javascript
复制
PUT properties-hybrid 
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "english"
      },
      "description": {
        "type": "text",
        "analyzer": "english",
        "copy_to": "semantic_field"
      },
      "neighborhood": {
        "type": "keyword"
      },
      "bedrooms": {
        "type": "integer"
      },
      "bathrooms": {
        "type": "integer"
      },
      "semantic_field": {
        "type": "semantic_text",
        "inference_id": "my-elser-model"
      }
    }
  }
}

索引数据

代码语言:javascript
复制
POST _bulk
{ "index" : { "_index" : "properties-hybrid" , "_id": "1"} }
{ "title": "Sunnydale 2室2卫", "description": "宽敞的公寓,现代设施,适合城市居民。", "neighborhood": "Sunnydale", "bedrooms": 2, "bathrooms": 2 }
{ "index" : { "_index" : "properties-hybrid", "_id": "2" } }
{ "title": "Sunnydale 1室1卫", "description": "紧凑的公寓,方便前往市中心,适合单身或情侣。", "neighborhood": "Sunnydale", "bedrooms": 1, "bathrooms": 1 }
{ "index" : { "_index" : "properties-hybrid", "_id": "3" } }
{ "title": "Pinewood 2室2卫", "description": "新公寓,现代卧室,位于餐厅和酒吧区。适合喜欢夜生活的活跃人士。", "neighborhood": "Pinewood", "bedrooms": 2, "bathrooms": 2 }
{ "index" : { "_index" : "properties-hybrid", "_id": "4" } }
{ "title": "Pinewood 3室2卫", "description": "隐蔽和私密的家庭单位,实用布局,共有三间房。靠近学校和商店。非常适合抚养孩子。", "neighborhood": "Pinewood", "bedrooms": 3, "bathrooms": 2 }
{ "index" : { "_index" : "properties-hybrid", "_id": "5" } }
{ "title": "Pinewood 2室2卫", "description": "安静的社区中的退休公寓,非常适合寻找安静的避风港的人。这处维护良好的住宅有两个卧室,充满自然光和宁静。", "neighborhood": "Pinewood", "bedrooms": 2, "bathrooms": 2 }
{ "index" : { "_index" : "properties-hybrid", "_id": "6" } }
{ "title": "Pinewood 1室1卫", "description": "景色优美的公寓,适合喜欢充满活力环境的人。", "neighborhood": "Pinewood", "bedrooms": 1, "bathrooms": 1 }
{ "index" : { "_index" : "properties-hybrid", "_id": "7" } }
{ "title": "Maplewood 2室2卫", "description": "宽敞的阳台,提供轻松舒适的生活体验。", "neighborhood": "Maplewood", "bedrooms": 2, "bathrooms": 2 }
{ "index" : { "_index" : "properties-hybrid", "_id": "8" } }
{ "title": "Maplewood 1室1卫", "description": "现代化室内设计的迷人公寓,位于安静的社区。", "neighborhood": "Maplewood", "bedrooms": 1, "bathrooms": 1 }

查询数据

我们先从经典的 match 查询开始,该查询将通过标题和描述的内容进行搜索:

代码语言:javascript
复制
GET properties-hybrid/_search
{
  "query": {
    "multi_match": {
      "query": "Pinewood 2室安静的地方",
      "fields": ["title", "description"]
    }
  }
}

这是第一个结果:

代码语言:javascript
复制
{
  "description": "新公寓,现代卧室,位于餐厅和酒吧区。适合喜欢夜生活的活跃人士。",
  "title": "Pinewood 2室2卫"
}

结果不算太差,匹配了 Pinewood2室 的要求,但这并不是一个安静的地方。

接下来是纯语义查询:

代码语言:javascript
复制
GET properties-hybrid/_search
{
  "query": {
    "semantic": {
      "field": "semantic_field",
      "query": "Pinewood 2室安静的地方"
    }
  }
}

这是第一个结果:

代码语言:javascript
复制
{
  "description": "隐蔽和私密的家庭单位,实用布局,共有三间房。靠近学校和商店。非常适合抚养孩子。",
  "title": "Pinewood 3室2卫"
}

这个结果考虑到了 安静的地方,通过“隐蔽和私密”来关联,但这是一个 3 室的,而我们需要的是 2 室。

现在我们运行一个混合搜索。我们将使用 RRF (Reciprocal rank fusion) 来实现这一目的,并结合前面的两个查询。RRF 算法将为我们融合两次查询的得分。

代码语言:javascript
复制
GET properties-hybrid/_search
{
  "retriever": {
    "rrf": {
      "retrievers": [
        {
          "standard": {
            "query": {
              "semantic": {
                "field": "semantic_field",
                "query": "Pinewood 2室安静的地方"
              }
            }
          }
        },
        {
          "standard": {
            "query": {
              "multi_match": {
                "query": "Pinewood 2室安静的地方",
                "fields": ["title", "description"]
              }
            }
          }
        }
      ],
      "rank_window_size": 50,
      "rank_constant": 20
    }
  }
}

这是第一个结果:

代码语言:javascript
复制
{
  "description": "安静的社区中的退休公寓,非常适合寻找安静的避风港的人。这处维护良好的住宅有两个卧室,充满自然光和宁静。",
  "title": "Pinewood 2室2卫"
}

现在结果考虑到了安静的环境,同时也有 2 间卧室的要求。

评估结果

为了评估,我们将使用 Ranking Evaluation API,它允许我们自动化运行查询并检查相关结果的位置。你可以选择不同的评估指标。在这个示例中,我将选择 平均倒数排名 (MRR),它考虑了结果的位置,并随着位置的降低而减少得分。

在这个场景中,我们将针对最初的问题测试我们的 3 个查询(multi_matchsemantichybrid):

Pinewood 2室安静的地方

我们期望以下公寓排在第一位,因为它满足所有条件。

“安静的社区中的退休公寓,非常适合寻找安静的避风港的人。这处维护良好的住宅有两个卧室,充满自然光和宁静。”

我们可以根据需要配置多个查询,并将我们期望排在首位的文档 ID 进行评分:

代码语言:javascript
复制
GET /properties-hybrid/_rank_eval
{
  "requests": [
    {
      "id": "hybrid",
      "request": {
        "retriever": {
          "rrf": {
            "retrievers": [
              {
                "standard": {
                  "query": {
                    "semantic": {
                      "field": "semantic_field",
                      "query": "Pinewood 2室安静的地方"
                    }
                  }
                }
              },
              {
                "standard": {
                  "query": {
                    "multi_match": {
                      "query": "Pinewood 2室安静的地方",
                      "fields": [
                        "title",
                        "description"
                      ]
                    }
                  }
                }
              }
            ],
            "rank_window_size": 50,
            "rank_constant": 20
          }
        }
      },
      "ratings": [
        {
          "_index": "properties-hybrid",
          "_id": "5",
          "rating": 1
        }
      ]
    },
    {
      "id": "lexical",
      "request": {
        "query": {
          "multi_match": {
            "query": "Pinewood 2室安静的地方",
            "fields": [
              "title",
              "description"
            ]
          }
        }
      },
      "ratings": [
        {
          "_index": "properties-hybrid",
          "_id": "5",
          "rating": 1
        }
      ]
    },
    {
      "id": "semantic",
      "request": {
        "query": {
          "semantic": {
            "field": "semantic_field",
            "query": "Pinewood 2室安静的地方"
          }
        }
      },
      "ratings": [
        {
          "_index": "properties-hybrid",
          "_id": "5",
          "rating": 1
        }
      ]
    }
  ],
  "metric": {
    "mean_reciprocal_rank": {
      "k": 20,
      "relevant_rating_threshold": 1
    }
  }
}
排名结果
排名结果

如图所示,混合搜索的查询得分为1(第1位),而其他的得分为0.5(第2位),说明期望结果排在第二位。

结论

全文搜索技术——通过术语找到并按术语频率排序结果——以及语义搜索——通过语义接近度进行搜索——在不同场景中各具优势。一方面,当用户明确知道自己想要搜索的内容时,如提供文章的确切SKU或技术手册中的词汇,文本搜索表现出色。另一方面,当用户寻找文档中未明确定义的概念或想法时,语义搜索非常有用。结合这两种方法的混合搜索,既提供了全文搜索的能力,又添加了语义相关的文档,这在需要关键词匹配和上下文理解的特定场景中非常有用。这个双重方法增强了搜索的准确性和相关性,使其非常适合处理复杂查询和多样化的内容类型。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是混合搜索?
  • 配置 ELSER
  • 配置索引
  • 索引数据
  • 查询数据
  • 评估结果
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档