如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x

这篇具有很好参考价值的文章主要介绍了如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

大型语言模型(LLM)每天都在发展,这种情况有助于语义搜索的扩展。 LLM 擅长分析文本和揭示语义相似性。 这种情况也反映在搜索引擎上,因为语义搜索引擎可以为用户提供更满意的结果。

尽管大型语言模型可以捕获语义上接近的结果,但在搜索结果中实施过滤器对于增强用户体验至关重要。 例如,合并基于日期或类别的过滤器可以显着提高更令人满意的搜索体验。 那么,如何才能有效地将语义搜索与过滤结合起来呢?

在今天的展示中,我将使用最新的 Elastic Stack 8.9.0 来进行展示。为了方便大家学习,所有数据请在地址 https://github.com/liu-xiao-guo/elasticsearch-vector-search/ 进行下载。

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考我之前的文章:

  • 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch

  • Kibana:如何在 Linux,MacOS 及 Windows 上安装 Elastic 栈中的 Kibana

在安装的时候,我们选择最新的 Elastic Stack 8.x 来进行安装。在默认的情况下,Elasticsearch 是带有 HTTPS 安全访问的。在 Elasticsearch 第一次启动时,我们记录下超级用户 elastic 的用户名及密码:

✅ Elasticsearch security features have been automatically configured!
✅ Authentication is enabled and cluster connections are encrypted.
 
ℹ️  Password for the elastic user (reset with `bin/elasticsearch-reset-password -u elastic`):
  p1k6cT4a4bF+pFYf37Xx
 
ℹ️  HTTP CA certificate SHA-256 fingerprint:
  633bf7f6e4bf264e6a05d488af3c686b858fa63592dc83999a0d77f7e9fe5940
 
ℹ️  Configure Kibana to use this cluster:
• Run Kibana and click the configuration link in the terminal when Kibana starts.
• Copy the following enrollment token and paste it into Kibana in your browser (valid for the next 30 minutes):
  eyJ2ZXIiOiI4LjkuMCIsImFkciI6WyIxOTIuMTY4LjAuMzo5MjAwIl0sImZnciI6IjYzM2JmN2Y2ZTRiZjI2NGU2YTA1ZDQ4OGFmM2M2ODZiODU4ZmE2MzU5MmRjODM5OTlhMGQ3N2Y3ZTlmZTU5NDAiLCJrZXkiOiJ3WEE3MDRrQkxxWTFWWGY0QWRHbDpCa0VZVXZmaFFidWNPOFUxdXJwXzZnIn0=
 
ℹ️  Configure other nodes to join this cluster:
• On this node:
  ⁃ Create an enrollment token with `bin/elasticsearch-create-enrollment-token -s node`.
  ⁃ Uncomment the transport.host setting at the end of config/elasticsearch.yml.
  ⁃ Restart Elasticsearch.
• On other nodes:
  ⁃ Start Elasticsearch with `bin/elasticsearch --enrollment-token <token>`, using the enrollment token that you generated.

词汇搜索 - 基本搜索

让我们首先从 Elasticsearch 连接和基本搜索查询开始。我们使用 Python 进行展示。我们需要安装需要的 Python 包:

pip3 install elasticsearch
pip3 install Config

有关 Elasticsearch 的连接,请参考 “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x”。我们在下载的代码里修改如下的文件 simple.cfg:

simple.cfg

ES_PASSWORD: "p1k6cT4a4bF+pFYf37Xx"
ES_FINGERPRINT: "633bf7f6e4bf264e6a05d488af3c686b858fa63592dc83999a0d77f7e9fe5940"

上面的 ES_PASSWORD 是我们在 Elasticsearch 第一次启动时显示的密码,而 ES_FINGERPRINT 的值是 http_ca.crt 的 fingerprint。我们也可以在 Elasticsearch 第一次启动的时候看到。如果你已经找不到这个显示,那么你可以参考文章 “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x” 来了解如何获得这个。另外一种比较简单的方法就是打开 config/kibana.yml 这个文件:

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

我们使用 jupyter 来打开文件 es-intro.ipynb:

from elasticsearch import Elasticsearch
from config import Config

with open('simple.cfg') as f:
    cfg = Config(f)

print(cfg['ES_FINGERPRINT'])
print(cfg['ES_PASSWORD'])

client = Elasticsearch(
    'https://localhost:9200',
    ssl_assert_fingerprint = cfg['ES_FINGERPRINT'],
    basic_auth=('elastic', cfg['ES_PASSWORD'])
)

client.info()

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

很显然我们的代码连接到 Elasticsearch 是成功的。

我们使用如下的代码来读取文件:

import json
with open('data.json', 'r') as f:
    data = json.load(f)

for book in data:
    print(book)

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

我将在这篇文章中使用的数据集是由 ChatGPT 生成的,并遵循上述格式。

我们首先检查是否已经有 book_index 索引被创建。如果有,就删除该索引:

INDEX_NAME = "book_index"
 
if(client.indices.exists(index=INDEX_NAME)):
    print("The index has already existed, going to remove it")
    client.options(ignore_status=404).indices.delete(index=INDEX_NAME)

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

 我们使用如下的代码来写入数据到 Elasticsearch:

book_mappings = {
    "properties": {
        "title": {"type": "text"},
        "author": {"type": "text"},
        "date": {"type": "date"}
    }
}

client.indices.create(index = INDEX_NAME, mappings = book_mappings)

for each in data:
    client.index(index = INDEX_NAME, document = each)
client.indices.refresh()

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

上面显示已经写入 14 个文档。我们使用如下的代码来显示所有的文档:

# GET ALL DOCUMENTS
resp = client.search(index='book_index', query={"match_all": {}})
for hit in resp['hits']['hits']:
    print(hit['_source'])

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

 为了对索引中的文档应用过滤,我们需要修改 “query” 参数。 要搜索文本中的单词,我们将使用 “match” 关键字:

# FILTERING - MATCH
resp = client.search(index='book_index', 
                     query={
                         "match":
                         {"title": "Data"}
                     })
for hit in resp['hits']['hits']:
    print(hit['_score'], hit['_source'])

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

我们列出了索引中 “title” 字段中包含 “Data”一词的文档。

如果你想跨多个字段应用过滤,可以使用 “bool” 操作来实现。 如果你不希望某些字段影响搜索中的分数,你可以在 “filter” 中指定它们。

# FILTERING - COMBINE FILTERS
resp = client.search(index='book_index', 
                     query={
                         "bool": {
                             "must": [
                                #  {"match": {"title": "data"}},
                                 {"match": {"author": "Smith"}},
                                 {"range": {"date": {"gte": "2023-08-01"}}}
                             ]
                         }
                     })
for hit in resp['hits']['hits']:
    print(hit)
如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python
使用 bool 运算的 Elasticsearch 搜索查询

有关 Elasticsearch 查询的更多信息,你可以在此处查看。

现在,让我们创建包含文档向量的相同索引。 在这篇文章中,我将使用 Sentence-Transformers 库和 “all-mpnet-base-v2” 模型。 模型使用没有限制,因此你可以选择任何您想要的模型。 你可以在此处探索更多模型。

from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-mpnet-base-v2')
model

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

 我们通过如下的方式来查看模型的维度大小:

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

我们使用如下的代码来检查索引 vector_index 是否已经存在,如果已经存在那么久删除它:

INDEX_NAME_VECTOR = "vector_index"
if(client.indices.exists(index = INDEX_NAME_VECTOR)):
    print("The index has already existed, going to remove it")
    client.options(ignore_status=404).indices.delete(index = INDEX_NAME_VECTOR)
vector_mapping = {
    "properties": {
        "title": {"type": "text"},
        "author": {"type": "text"},
        "date": {"type": "date"},
        "vector": {
            "type": "dense_vector",
            "dims": 768,
            "index": True,
            "similarity": "dot_product"
        }
    }
}

client.indices.create(index = INDEX_NAME_VECTOR, mappings = vector_mapping)

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

这次创建 “vector_index” 时,我们添加了一个 “dense_vector” 类型的附加字段,并指定向量搜索的参数:“dims” 参数表示所用模型作为输出生成的矢量的维数。 “Similarity” 决定了衡量向量相似度的方法。 你可以在这里探索不同的 “similarity” 值。

for each in data:
    each['vector'] = model.encode(each['title'])
    client.index(index='vector_index', document=each)
client.indices.refresh()

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

让我们使用 Sentence-Transformers 库加载模型,并从数据集的 “title” 部分提取向量。 然后,我们将这些向量添加到每个数据条目中,并继续将此数据添加到 “vector_index” 索引中。

为了在 Elasticsearch 中执行向量搜索,我们首先需要一个查询文本,然后是其相应的向量表示。

重要提示:用于获取查询向量的模型应与索引文档时使用的模型相同; 否则,获得准确的结果将非常具有挑战性。

我们可以运行如下的代码来查看已经生成的 embeddings:

resp = client.search(index = INDEX_NAME_VECTOR, query={"match_all": {}})
for hit in resp['hits']['hits']:
    print(resp)

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

为了执行向量搜索,Elasticsearch.search() 函数使用 “knn” 参数。 下图显示了 “knn” 查询的示例。 “k” 值表示要检索多少个结果,而 “num_candidates” 指定将有多少候选文档放入池中进行计算。 “query_vector” 是查询文本的向量表示(在我们的例子中是 “HTML and CSS programming”)。 你可以在此处找到有关 knn 查询参数的详细信息。

query_text = "HTML and CSS programming"
query_vector = model.encode(query_text)
query = {
    "field": "vector",
    "query_vector": query_vector,
    "k": 5,
    "num_candidates": 14
}

resp = client.search(index='vector_index', knn=query, source=False, fields=['title'])
for hit in resp['hits']['hits']:
    print(hit['_score'], hit['fields'])

上面显示的结果为:

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

示例查询返回的结果如上图所示。 尽管返回的结果都不包含完全相同的单词,但它们已经成功捕获了语义相似的结果。

那么,如果我们还想将这些语义搜索结果与过滤结合使用,我们应该如何准备 knn 查询呢?

query = {
    "field": "vector",
    "query_vector": query_vector,
    "k": 5,
    "num_candidates": 14,
    "filter":[
        {"range": {"date": {"gte": "2023-07-01"}}},
        {"match": {"title": "Development"}}
    ]
}
resp = client.search(index='vector_index', knn=query, source=False, fields=['title'])
for hit in resp['hits']['hits']:
    print(hit['_score'], hit['fields'])

如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x,Elasticsearch,Elastic,elasticsearch,大数据,搜索引擎,人工智能,运维,python

我们应用的每个过滤器都作为 knn 参数中的 filter 提供。 你可以在此处添加任意数量的过滤器,并根据这些过滤器组合结果。 在上面的示例中,日期过滤器和关键字过滤器已添加在一起,旨在列出语义上接近且包含单词 Development 但日期晚于 2023 年 7 月 1 日的文档。

重要提示:Elasticsearch 在矢量搜索过程后执行过滤,因此可能存在无法返回精确 k 个结果的情况。 在上图中,即使 “k” 值设置为 5,查询仍返回 3 个文档作为结果。 这是因为,在准备的示例数据集中,只有 3 个文档满足指定的条件。

更多关于向量搜索的知识,请参考文章 “Elastic:开发者上手指南” 中的 “NLP - 自然语言处理及矢量搜索” 章节。文章来源地址https://www.toymoban.com/news/detail-654845.html

到了这里,关于如何在 Elasticsearch 中将矢量搜索与过滤结合起来 - Python 8.x的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch实战(十五)---查询query,filter过滤,结合aggs 进行局部/全局聚合统计

    Elasticsearch实战-查询query,filter过滤,结合aggs 进行局部/全局聚合统计 1.准备数据 2. ES 查询query,filter过滤,结合aggs 聚合统计 2.1 查询命中后,基于查询的数据进行聚合 前面我们讲的所有的聚合操作 都是没有查询的,都是上来直接 aggs 进行 聚合 avg, count, 如果现在我想统计

    2024年02月10日
    浏览(47)
  • 从物联网到AI智能,详解如何将物联网和AI技术结合起来

    作者:禅与计算机程序设计艺术 物联网(IoT)与人工智能(AI)相互促进、协同,推动着产业的前进。物联网的应用已经越来越广泛,比如自动化生产线,智能门禁系统等;而AI在物联网领域也取得了很大的发展,机器学习、深度学习方法被用在物联网数据分析、决策与预测上,实

    2024年02月07日
    浏览(35)
  • Elasticsearch:结合两全其美:Elasticsearch 与 BM25 和 HNSW 的混合搜索

    就搜索算法而言,没有万能的解决方案。 不同的算法在不同的场景下效果更好,有时需要算法的组合才能达到最好的效果。 在 Elasticsearch 中,一种流行的组合搜索算法的方法是使用混合搜索,将用于文本搜索的 BM25 算法与用于最近邻搜索的 HNSW 算法相结合。 在这篇博文中,

    2024年02月06日
    浏览(26)
  • fastapi结合Manticore Search、elasticsearch、mysql实现全文搜索

    创建测试表 测试表插入数据 表字段描述 字段意义 mysql数据同步到es es查看数据(Elasticvue插件)   mysql数据同步到Manticore 注:Manticore 和 Mysql 使用pymysql即mysql客户端 Manticore 数据查询(工具Webyog SQLyog)   es安全认证连接(参考官网) 按fields查询方法封装,输入参数fields 筛选器,

    2024年02月12日
    浏览(34)
  • 开源分布式搜索引擎ElasticSearch结合内网穿透远程连接

    简单几步,结合Cpolar 内网穿透工具实现Java 远程连接操作本地分布式搜索和数据分析引擎Elasticsearch。 Cpolar内网穿透提供了更高的安全性和隐私保护,通过使用加密通信通道,Cpolar技术可以确保数据传输的安全性,这为用户和团队提供了更可靠的保护,使他们能够放心地处理和

    2024年02月04日
    浏览(36)
  • ES es Elasticsearch 十三 Java api 实现搜索 分页查询 复杂查询 过滤查询 ids查询 等

    目录 Java api 实现搜索 Pom.xml 建立链接 搜索全部记录 增加规则值查某些字段 搜索分页 全代码 Ids 搜索 搜索Match搜索 multi_match 搜索 多字段搜索 复杂查询 bool查询 filter  bool 复杂查询增加过滤器查询 复杂擦好像加排序 日志 思路 参考 api 写法 写Java代码 请求条件构建层次

    2024年02月04日
    浏览(49)
  • 分布式搜索和分析引擎Elasticsearch本地部署结合内网穿透实现远程访问

    本文主要介绍如何在Windows系统部署分布式搜索和分析引擎Elasticsearch,并结合Cpolar内网穿透工具实现公网远程连接和访问本地服务。 Elasticsearch是一个基于Lucene库的分布式搜索和分析引擎,它提供了一个分布式、多租户的全文搜索引擎,具有HTTP Web接口和无模式JSON文档,同时也

    2024年01月21日
    浏览(36)
  • 项目1在线交流平台-6.Elasticsearch分布式搜索引擎-3.ES结合Kafka应用-开发社区搜索功能

    参考牛客网高级项目教程 狂神说Elasticsearch教程笔记 尚硅谷Elasticsearch教程笔记 1.在业务层处理好搜索帖子的服务 包括保存帖子到ES服务器 从服务器中删除帖子 从服务器中查询帖子 2.发布事件 在controller层,结合kafka,发布帖子、增加评论时,数据放入消息队列 异步消费消息

    2024年02月02日
    浏览(40)
  • 在 Excel 中将列数据用单引号括起来并添加分隔符的解决方案

            在 Excel 中,有时候我们需要将某一列的所有值连接在一起,并且每个值用单引号括起来,同时在每个值之间添加逗号和空格。这样的需求在数据处理和导出时比较常见。本文将介绍一种使用 Excel 函数解决这个问题的方法。 解决方案: 方法一:使用 CONCATENATE 和

    2024年01月20日
    浏览(29)
  • Elasticsearch:如何使用集群级别的分片分配过滤(不包括节点)安全地停用节点

    当你想停用 Elasticsearch 中的节点时,通常的过程不是直接销毁节点。 如果你这样做,那么你就有数据丢失的风险,这不是你想要对应该是可靠的数据库做的事情。 这样做的问题是,节点很可能会通过 Elasticsearch 处理的恰当命名的分片分配分配给它们的分片。 Elasticsearch 中的

    2024年02月07日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包