Redis 作为向量数据库快速入门指南

打印 上一主题 下一主题

主题 801|帖子 801|积分 2403

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,不由得分享一下给各人。点击跳转到网站。
本快速入门指南可帮助您:

  • 了解什么是向量数据库
  • 创建 Redis 向量数据库
  • 创建向量嵌入并存储向量
  • 查询数据并实行矢量搜索
了解向量数据库

数据通常黑白布局化的,这意味着它没有由界说精良的架构描述。非布局化数据的示例包括文本段落、图像、视频或音频。存储和搜索非布局化数据的一种方法是使用向量嵌入。
什么是向量?在机器学习和人工智能中,向量是表现数据的数字序列。它们是模型的输入和输出,以数字形式封装基础信息。矢量将非布局化数据(如文本、图像、视频和音频)转换为机器学习模型可以处理的格式。
为什么它们很重要?向量捕捉数据中固有的复杂模式和语义含义,使其成为各种应用程序的强盛工具。它们允许机器学习模型更有效地理解和操作非布局化数据。
增强传统搜索。传统的关键字或词汇搜索依赖于单词或短语的精确匹配,这可能会受到限制。相比之下,向量搜索或语义搜索使用了向量嵌入中捕捉的丰富信息。通过将数据映射到向量空间中,相似的项目根据其含义彼此靠近放置。这种方法允许更正确和有意义的搜索结果,由于它考虑了查询的上下文和语义内容,而不仅仅是使用简直切单词。
创建 Redis 向量数据库

您可以将 Redis Stack 用作向量数据库。它允许您:


  • 将向量和关联的元数据存储在哈希或 JSON 文档中
  • 创建和配置用于搜索的二级索引
  • 实行矢量搜索
  • 更新矢量和元数据
  • 删除和清理
安装所需的 Python 包

创建一个 Python 虚拟情况,并使用以下下令安装 pip 以下依赖项:


  • redis :您可以在本文档站点的客户端部门找到有关客户端库的 redis-py 更多具体信息。
  • pandas :Pandas 是一个数据分析库。
  • sentence-transformers :您将使用 SentenceTransformers 框架在全文上天生嵌入。
  • tabulate : pandas 用于 tabulate 渲染 Markdown。
您还必要在 Python 代码中导入以下内容:
  1. import json
  2. import time
  3. import numpy as np
  4. import pandas as pd
  5. import requests
  6. import redis
  7. from redis.commands.search.field import (
  8.     NumericField,
  9.     TagField,
  10.     TextField,
  11.     VectorField,
  12. )
  13. from redis.commands.search.indexDefinition import IndexDefinition, IndexType
  14. from redis.commands.search.query import Query
  15. from sentence_transformers import SentenceTransformer
复制代码
连接

连接到 Redis。默认情况下,Redis 返回二进制相应。要对它们举行解码,请将 decode_responses 参数集传递给 True :
  1. client = redis.Redis(host="localhost", port=6379, decode_responses=True)
复制代码
预备演示数据集

本快速入门指南还使用了自行车数据集。下面是其中的示例文档:
  1. {
  2.   "model": "Jigger",
  3.   "brand": "Velorim",
  4.   "price": 270,
  5.   "type": "Kids bikes",
  6.   "specs": {
  7.     "material": "aluminium",
  8.     "weight": "10"
  9.   },
  10.   "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! ..."
  11. }
复制代码
该 description 字段包含自行车的自由格式文本描述,将用于创建矢量嵌入。
1. 获取演示数据

您必要首先将演示数据集作为 JSON 数组获取:
  1. URL = ("https://raw.githubusercontent.com/bsbodden/redis_vss_getting_started"
  2.        "/main/data/bikes.json"
  3.        )
  4. response = requests.get(URL, timeout=10)
  5. bikes = response.json()
复制代码
检查其中一个自行车 JSON 文档的布局:
  1. json.dumps(bikes[0], indent=2)
复制代码
2. 将演示数据存储在 Redis 中

现在,使用 JSON 遍历 bikes 数组,将数据作为 JSON 文档存储在 Redis 中。SET 下令。以下代码使用管道来最大水平地减少网络往返时间:
  1. pipeline = client.pipeline()
  2. for i, bike in enumerate(bikes, start=1):
  3.     redis_key = f"bikes:{i:03}"
  4.     pipeline.json().set(redis_key, "$", bike)
  5. res = pipeline.execute()
  6. # >>> [True, True, True, True, True, True, True, True, True, True, True]
复制代码
加载后,您可以使用 JSONPath 表达式从 Redis 中的某个 JSON 文档中检索特定属性:
  1. res = client.json().get("bikes:010", "$.model")
  2. # >>> ['Summit']
复制代码
3. 选择文本嵌入模型

HuggingFace 有大量的文本嵌入模型目次,这些模型可通过 SentenceTransformers 框架在本地提供服务。在这里,我们使用广泛用于搜索引擎、谈天机器人和其他 AI 应用程序的 MS MARCO 模型。
  1. from sentence_transformers import SentenceTransformer
  2. embedder = SentenceTransformer('msmarco-distilbert-base-v4')
复制代码
4. 天生文本嵌入

遍历所有 Redis 键,前缀 bikes: 为:
  1. keys = sorted(client.keys("bikes:*"))
  2. # >>> ['bikes:001', 'bikes:002', ..., 'bikes:011']
复制代码
使用键作为 JSON 的输入。MGET 下令以及 $.description 字段,用于收集列表中的描述。然后,将说明列表传递给 .encode() 该方法:
  1. descriptions = client.json().mget(keys, "$.description")
  2. descriptions = [item for sublist in descriptions for item in sublist]
  3. embedder = SentenceTransformer("msmarco-distilbert-base-v4")
  4. embeddings = embedder.encode(descriptions).astype(np.float32).tolist()
  5. VECTOR_DIMENSION = len(embeddings[0])
  6. # >>> 768
复制代码
使用 JSON 将矢量化描述插入到 Redis 中的自行车文档中。SET 下令。以下下令将一个新字段插入到 JSONPath 下的每个文档 $.description_embeddings 中。再一次,使用管道实行此操作,以避免不须要的网络往返:
  1. pipeline = client.pipeline()
  2. for key, embedding in zip(keys, embeddings):
  3.     pipeline.json().set(key, "$.description_embeddings", embedding)
  4. pipeline.execute()
  5. # >>> [True, True, True, True, True, True, True, True, True, True, True]
复制代码
使用 JSON 检查更新的自行车文档之一。GET 下令:
  1. res = client.json().get("bikes:010")
  2. # >>>
  3. # {
  4. #   "model": "Summit",
  5. #   "brand": "nHill",
  6. #   "price": 1200,
  7. #   "type": "Mountain Bike",
  8. #   "specs": {
  9. #     "material": "alloy",
  10. #     "weight": "11.3"
  11. #   },
  12. #   "description": "This budget mountain bike from nHill performs well..."
  13. #   "description_embeddings": [
  14. #     -0.538114607334137,
  15. #     -0.49465855956077576,
  16. #     -0.025176964700222015,
  17. #     ...
  18. #   ]
  19. # }
复制代码
  在 JSON 文档中存储矢量嵌入时,嵌入存储为 JSON 数组。在上面的示例中,为了便于阅读,数组被大大缩短。
  创建索引

1. 创建带有向量字段的索引

必须创建索引才能查询文档元数据或实行矢量搜索。使用 FT.CREATE 下令:
  1. FT.CREATE idx:bikes_vss ON JSON
  2.   PREFIX 1 bikes: SCORE 1.0
  3.   SCHEMA
  4.     $.model TEXT WEIGHT 1.0 NOSTEM
  5.     $.brand TEXT WEIGHT 1.0 NOSTEM
  6.     $.price NUMERIC
  7.     $.type TAG SEPARATOR ","
  8.     $.description AS description TEXT WEIGHT 1.0
  9.     $.description_embeddings AS vector VECTOR FLAT 6 TYPE FLOAT32 DIM 768 DISTANCE_METRIC COSINE
复制代码
以下是 VECTOR 字段界说的细分:


  • $.description_embeddings AS vector :向量字段的 JSON 路径及其字段别名 vector 。
  • FLAT :指定索引方法,该方法可以是平面索引,也可以是分层可导航的小天下图 (HNSW)。
  • TYPE FLOAT32 :设置向量分量的浮点精度,在本例中为 32 位浮点数。
  • DIM 768 :嵌入的长度或尺寸,由所选的嵌入模型确定。
  • DISTANCE_METRIC COSINE :所选距离函数:余弦距离。
您可以在矢量参考文档中找到有关所有这些选项的更多具体信息。
2. 检查索引的状态

一旦您实行 FT.CREATE 下令,索引过程在背景运行。在很短的时间内,所有 JSON 文档都应该被索引并预备好举行查询。若要验证这一点,可以使用 FT.INFO 下令,该下令提供有关索引的具体信息和统计信息。特别值得一提的是乐成编制索引的文档数目和失败的文档数目:
  1. FT.INFO idx:bikes_vss
复制代码
实行矢量搜索

本快速入门指南重点介绍矢量搜索。但是,您可以在文档数据库快速入门指南中了解有关如何基于文档元数据举行查询的具体信息。
1. 嵌入您的查询

以下代码片段表现了将用于在 Redis 中实行矢量搜索的文本查询列表:
  1. queries = [
  2.     "Bike for small kids",
  3.     "Best Mountain bikes for kids",
  4.     "Cheap Mountain bike for kids",
  5.     "Female specific mountain bike",
  6.     "Road bike for beginners",
  7.     "Commuter bike for people over 60",
  8.     "Comfortable commuter bike",
  9.     "Good bike for college students",
  10.     "Mountain bike for beginners",
  11.     "Vintage bike",
  12.     "Comfortable city bike",
  13. ]
复制代码
首先,使用雷同的 SentenceTransformers 模型将每个输入查询编码为向量嵌入:
  1. encoded_queries = embedder.encode(queries)
  2. len(encoded_queries)
  3. # >>> 11
复制代码
  使用与嵌入文档雷同的嵌入模型来嵌入查询至关重要。使用不同的模型将导致语义搜索结果不佳或错误。
  2. K-近来邻 (KNN) 搜索

KNN 算法根据所选的距离函数计算查询向量与 Redis 中每个向量之间的距离。然后,它返回与查询向量距离最小的前 K 项。这些是语义上最相似的项目。
现在构造一个查询来做到这一点:
  1. query = (
  2.     Query('(*)=>[KNN 3 @vector $query_vector AS vector_score]')
  3.      .sort_by('vector_score')
  4.      .return_fields('vector_score', 'id', 'brand', 'model', 'description')
  5.      .dialect(2)
  6. )
复制代码
让我们分解上面的查询模板:


  • filter 表达式的 (*) 意思是 all 。换言之,未应用任何过滤。您可以将其更换为按其他元数据举行筛选的表达式。
  • 查询 KNN 的部门搜索前 3 个近来邻。
  • 查询向量必须作为参数传入 query_vector 。
  • 到查询向量的距离返回为 vector_score 。
  • 结果按以下 vector_score 方式排序。
  • 最后,它返回每个结果的字段 vector_score 、 id 、 brand 和 model description 。
   若要在 FT.SEARCH 下令中使用向量查询,必须指定 DIALECT 2 或更高版本。
  您必须将矢量化查询作为参数名称 query_vector 为 的字节数组传递。以下代码从查询向量创建一个 Python NumPy 数组,并将其转换为可作为参数传递给查询的紧凑的字节级表现形式:
  1. client.ft('idx:bikes_vss').search(
  2.     query,
  3.     {
  4.       'query_vector': np.array(encoded_query, dtype=np.float32).tobytes()
  5.     }
  6. ).docs
复制代码
有了查询模板后,可以在循环中实行所有查询。请留意,该脚本将每个结果的计算值 vector_score 为 1 - doc.vector_score 。由于余弦距离用作度量,因此距离最小的项更近,因此与查询更相似。
然后,遍历匹配的文档并创建一个结果列表,该列表可以转换为 Pandas 表以可视化结果:
  1. def create_query_table(query, queries, encoded_queries, extra_params=None):
  2.     """
  3.     Creates a query table.
  4.     """
  5.     results_list = []
  6.     for i, encoded_query in enumerate(encoded_queries):
  7.         result_docs = (
  8.             client.ft("idx:bikes_vss")
  9.             .search(
  10.                 query,
  11.                 {"query_vector": np.array(encoded_query, dtype=np.float32).tobytes()}
  12.                 | (extra_params if extra_params else {}),
  13.             )
  14.             .docs
  15.         )
  16.         for doc in result_docs:
  17.             vector_score = round(1 - float(doc.vector_score), 2)
  18.             results_list.append(
  19.                 {
  20.                     "query": queries[i],
  21.                     "score": vector_score,
  22.                     "id": doc.id,
  23.                     "brand": doc.brand,
  24.                     "model": doc.model,
  25.                     "description": doc.description,
  26.                 }
  27.             )
  28.     # Optional: convert the table to Markdown using Pandas
  29.     queries_table = pd.DataFrame(results_list)
  30.     queries_table.sort_values(
  31.         by=["query", "score"], ascending=[True, False], inplace=True
  32.     )
  33.     queries_table["query"] = queries_table.groupby("query")["query"].transform(
  34.         lambda x: [x.iloc[0]] + [""] * (len(x) - 1)
  35.     )
  36.     queries_table["description"] = queries_table["description"].apply(
  37.         lambda x: (x[:497] + "...") if len(x) > 500 else x
  38.     )
  39.     return queries_table.to_markdown(index=False)
复制代码
查询结果表现各个查询的前三个匹配项(我们的 K 参数)以及每个查询的自行车 ID、品牌和型号。
例如,对于查询“最适合儿童的山地自行车”,相似度得分最高 ( 0.54 ),因此最靠近的匹配项是“Nord”品牌的“Chook air 5”自行车型号,描述为:
   Chook Air 5 为 6 岁及以上的孩子提供了一辆耐用且超轻便的山地自行车,让他们第一次体验赛道,并在森林和旷野中轻松巡航。下部顶部管便于在任何情况下安装和拆卸,让您的孩子在小径上更加安全。Chook Air 5 是山地自行车的完美入门。
  从描述来看,这款自行车非常适合年幼的孩子,并且嵌入正确地捕捉了描述的语义。
  1. query = (
  2.     Query("(*)=>[KNN 3 @vector $query_vector AS vector_score]")
  3.     .sort_by("vector_score")
  4.     .return_fields("vector_score", "id", "brand", "model", "description")
  5.     .dialect(2)
  6. )
  7. table = create_query_table(query, queries, encoded_queries)
  8. print(table)
  9. # >>> | Best Mountain bikes for kids     |    0.54 | bikes:003...
复制代码
后续步骤


  • 您可以通过阅读矢量参考文档来了解有关查询选项(如筛选器和矢量范围查询)的更多信息。
  • 完整的搜索和查询文档可能会让您感兴趣。
  • 如果要以交互方式遵循代码示例,则可以使用开导本快速入门指南的 Jupyter 条记本。
  • 如果您想查看 Redis 向量数据库的更多高级示例,请访问 GitHub 上的 Redis AI 资源页面。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊落一身雪

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表