使用 Elasticsearch 作为 Azure OpenAI On Your Data 的向量数据库

2024年6月3日   |   by mebius

作者:来自 ElasticPaul Oremland

背景介绍

最近,微软通过 Azure OpenAI 服务 “On Your Data” 将 Elasticsearch 直接集成到 Azure 中。”On Your Data” 使组织能够利用强大的 AI 模型(如 GPT-4 和 RAG 模型)构建最先进的对话体验。这样可以让大型语言模型基于你的私有数据,从而确保对话内容的知情性和准确性。

在本文中,我想展示如何轻松启动一个 Elasticsearch 集群,使用 Elasticsearch 连接器来摄取数据,然后通过新的 Azure OpenAI 服务 “On Your Data” 集成来与这些数据进行对话。我们将在本文中使用的一个工具是最近新增的 Connectors API 和 CLI,这使我们能够完全通过编程方式与 Elasticsearch 进行交互,而无需在开发环境和 Kibana 之间来回切换。

%title插图%num

先决条件

在本示例中,我将使用 https://openlibrary.org 中的 OpenLibrary 数据集。 为了使用此数据集,你需要做一些前期工作,让数据准备好摄取到 Elasticsearch 中。 具体来说,你需要:

  1. https://openlibrary.org/developers/dumps 下载最新的数据转储
  2. 将数据转储导入 PostgreSQL。 我使用了 https://github.com/LibrariesHacked/openlibrary-search 中列出的开源工具和步骤

虽然步骤 2 并不是绝对必要的,因为你可以编写自定义摄取脚本,但出于几个原因,我喜欢将数据暂存在 PostgreSQL 中。 首先,Elasticsearch 开箱即用地支持通过连接器从 PostgreSQL 获取数据。 连接器已经针对吞吐量进行了优化,并且内置了一些很好的弹性,我讨厌重新发明轮子。 其次,我可以编写自定义 SQL 查询以与连接器一起使用。 这意味着我有很大的灵活性,可以从数据集中仅提取我想要的数据,并且可以将 “book” 的高度规范化的数据表示为单个文档,而无需编写自定义代码来从原始参考数据转储中执行此操作。 因此,我不必花几天时间编写和调整自定义脚本来创建代表书籍的版本、作者和作品的单个文档,而是只需花费几分钟将数据导入 PostgreSQL 并设置连接器将数据提取到 Elasticsearch 中。

启动 Elasticsearch 集群

现在我已经准备好所有要摄取的数据,我将创建一个 Elasticsearch 部署。我选择使用 Elastic Cloud,因为我不想担心或管理任何基础设施。

注意,我将主要通过命令行和 curl 来完成大部分操作。我会使用一些需要在命令行中导出的 shell 变量,具体包括:

  • ES_URL:你的 Elasticsearch 部署的 URL
  • API_KEY:我们在后续步骤中创建的密钥
  • CONNECTOR_ID:在后续步骤中创建的连接器 ID

第一步是在 .https://cloud.elastic.co/deployments/create或者通过 API 创建一个部署。因为我知道我会对数百万文档生成嵌入并在查询中执行文本扩展,所以我要将机器学习实例的最小大小增加到 4GB。

展开 “Advanced settings” 部分。

%title插图%num

向下滚动到机器学习实例并将 “Minimum size per zone” 更新为 4GB

%title插图%num

现在你可以单击 “Create deployment” 按钮。 稍后你的部署就会完成。

接下来,让我们创建一个 API 密钥。 请记住将其保存在安全的地方,因为我们会经常使用它。 请注意,为了使这个示例简单,我使用了过于宽松的访问权限。 在实践中(和在生产中),你可能希望使用角色和/或限制来设置更细粒度的权限

curl --user elastic -X PUT "${ES_URL}/_security/api_key?pretty" 
-H "Content-Type: application/json" 
-d'
{
    "name": "books-api-key",
    "role_descriptors": {
        "role-name": {
            "cluster": ["all"],
            "index": [ { "names": ["*"], "privileges": ["all"] } ]
        }
    }
}
'

接下来,你需要创建索引并为 title 和 descriptions 字段设置 dense_vector 映射。 此步骤假设你知道文档架构,这会产生一种“先有鸡还是先有蛋”的问题,因为直到摄取数据之后你才知道该架构。 为了简单起见,我使用下面列出的相同步骤设置了一个临时索引,创建了一个连接器,并提取了一个文档(将 SQL 查询的限制设置为 1)。 这使我能够知道文档 schema 是什么样子,这样我就可以在开始时生成我想要的映射。 这是我们团队正在努力在未来版本中解决的已知尖锐问题。

curl -X PUT "${ES_URL}/books-index?pretty" 
-H "Authorization: ApiKey "${API_KEY}"" 
-H "Content-Type: application/json" 
-d'
{
    "mappings": {
        "properties": {
            "public_author_works_authors_edition_isbns_editions_works_description": {
                "type": "text",
                "copy_to": ["description"]
            },
            "public_author_works_authors_edition_isbns_editions_works_title": {
                "type": "text",
                "copy_to": ["title"]
            },
            "description": { "type": "text" },
            "title": { "type": "text" },
            "title_embedding": { "type": "dense_vector" },
            "description_embedding": { "type": "dense_vector" }
        }
    }
}
'

现在我们已经创建了索引并设置了映射,让我们下载 Etgcode5 模型并将输入字段名称设置为我们刚刚创建的密集向量映射。

curl -X PUT "${ES_URL}/_ml/trained_models/.multilingual-e5-small_linux-x86_64?pretty" 
-H "Authorization: ApiKey "${API_KEY}"" 
-H "Content-Type: application/json" 
-d'
{
    "input": {
        "field_names": ["title_embedding", "description_embedding"]
    }
}
'

接下来我们要部署模型。 如果你收到 408,则需要在执行上一个命令后等待一分钟,以便首先完成下载。

curl -X POST "${ES_URL}/_ml/trained_models/.multilingual-e5-small_linux-x86_64/deployment/_start?wait_for=started&deploymtgcodeent_id=for_search&pretty" -H "Authorization: ApiKey "${API_KEY}""

最后,我们需要创建一个推理管道,当我们从连接器获取数据时,该管道将在 title 和 decription 字段上创建嵌入。

curl -X PUT "${ES_URL}/_ingest/pipeline/e5-small-books?pretty" 
-H "Authorization: ApiKey "${API_KEY}"" 
-H "Content-Type: application/json" 
-d'
{
    "processors": [{
        "inference": {
            "model_id": "for_search",
            "input_output": [
                {
                    "input_field": "public_author_works_authors_edition_isbns_editions_works_title",
                    "output_field": "title_embedding"
                },
                {
                    "input_field": "public_author_works_authors_edition_isbns_editions_works_description",
                    "output_field": "description_embedding"
                }
            ]
        }
    }]
}
'

摄取数据

现在我们已经创建、配置了集群并准备使用,让我们开始提取数据。 为此,我们将使用 Elasticsearch PostgreSQL 连接器。 我将从源代码中执行此操作,因为为什么不呢,但如果你想要更多开箱即用的东西,你可以从 Docker 安装

首先,让我们克隆 GitHub 存储库并安装所有依赖项。

git clone git@github.com:elastic/connectors.git
cd connectors && make clean install

接下来,我将使用神奇的连接器 CLI 对我的 Elasticsearch 实例进行身份验证,并让它处理基本的连接器配置。 第一步是通过 CLI 登录 Elasticsearch,并在出现提示时输入你的 Elasticsearch 实例 URL 和 API 密钥。

./bin/connectors login --method apikey

接下来,创建连接器并在出现提示时输入 PostgreSQL 连接信息。

./bin/connectors connector create 
--from-index 
--index-name books-index 
--service-type postgresql 
--index-language en 
--update-config

? Connector name: books-postgresql-connector
? Host []: localhost
? Port []: 5432
? Username []: 
? Password []: 
? Database []: openlibrary
? Schema []: public
? Comma-separated list of tables []: *
? Rows fetched per request []:
? Retries per request []:
? Enable SSL verification [False]:

因为我们的数据源有大量标准化数据,所以我们需要创建一个自定义 SQL 语句,我们可以将连接器配置为与其高级同步规则功能一起使用。 我们将使用以下 SQL 语句来帮助我们从高度相关的数据创建单个文档。 请注意,由于此 SQL 将通过 curl 命令发送,因此我们需要使用 ”’ 转义 ‘。

SELECT DISTINCT ON (author_works.work_key, editions.data->>'''publish_date''') author_works.author_key, 
  editions.key, 
  author_works.author_key, 
  author_works.work_key, 
  edition_isbns.edition_key, 
  edition_isbns.isbn, 
  authors.key, 
  works.key, 
  works.data->>'''title''' AS title, 
  authors.data->>'''name''' AS author_name, 
  COALESCE(works.data->'''description'''->>'''value''', '''''') AS description, 
  edition_isbns.isbn AS isbn, 
  editions.data->>'''publish_date''' as publish_date 
FROM editions 
  JOIN edition_isbns on edition_isbns.edition_key = editions.key 
  JOIN works on works.key = editions.work_key 
  JOIN author_works on author_works.work_key = works.key 
  JOIN authors on author_works.author_key = authors.key 
WHERE 
  EXISTS (SELECT 1 FROM jsonb_array_elements(editions.data->'''languages''') AS elem WHERE elem->>'''key''' = '''/languages/eng''') 
ORDER BY 
  editions.data->>'''publish_date''' desc

起草高级同步规则。 连接器运行后,被创建的同步规则将在通过验证后激活。

注意:此 API 调用当前在 Elasticsearch Serverless 中可用,并将包含在 Elasticsearch 8.14 版本中。

curl -X PUT "${ES_URL}/_connector/${CONNECTOR_ID}/_filtering?pretty" 
-H "Authorization: ApiKey "${API_KEY}"" 
-H "Content-Type: application/json" 
-d'
{
    "advanced_snippet": {
        "value": [{
            "tables": [ "editions", "works", "author_works", "authors", "edition_isbns" ],
            "query": ""
        }]
    }
}
'

我们还希望将连接器连接到我们之前创建的推理管道,以便在摄取文档时自动生成嵌入。

curl -X PUT "${ES_URL}/_connector/${CONNECTOR_ID}/_pipeline?pretty" 
-H "Authorization: ApiKey "${API_KEY}"" 
-H "Content-Type: application/json" 
-d'
{
    "pipeline": {
        "extract_binary_content": true,
        "name": "e5-small-books",
        "reduce_whitespace": true,
        "run_ml_inference": true
    }
}
'

接下来,我们将使用 API 启动同步,将数据提取到 Elasticsearch 中。

curl -X POST "${ES_URL}/_connector/_sync_job?pretty" 
-H "Authorization: ApiKey "${API_KEY}"" 
-H "Content-Type: application/json" 
-d'
{
    "id": $CONNECTOR_ID,
    "job_type": "full"
}
'

最后,是时候运行连接器了:

make run

你可以使用以下命令检查摄取了多少文档:

curl -X POST "${ES_URL}/books-index/_count&pretgcodetty" -H "Authorization: ApiKey "${API_KEY}""

将 Azure OpenAI On Your Data 连接到 Elasticsearch

现在我们已经部署了 Elasticsearch 并提取了所有数据,让我们使用 Azure OpenAI 服务的 “On Your Data” 与索引进行对话。 为此,我将使用 Azure OpenAI 控制台。

我们需要做的第一件事是打开 Azure AI Studio 的 Web 界面并:

  1. 打开 “Chat” 游乐场
  2. 选择 “Add your data” 选项卡
  3. 单击 “Add your data source” 按钮

%title插图%num

接下来,选择 Elasticsearch 作为你的数据源,然后:

  1. 输入你的 Elasticsearch 端点 URL(上面的 $ES_URL)
  2. 输入你的 API 密钥(上面的 $API_KEY)
  3. 单击 “Verify connection” 按钮
  4. 选择你的 books-index
  5. 选中 “Use custom field mapping” 按钮
  6. 单击 “Next” 按钮

%title插图%num

%title插图%num

接下来,我们将通过以下方式设置搜索类型和嵌入模型:

  1. 从 Search type 下拉列表中选择 “Vector”
  2. 选择 “Elasticsearch – .multilingual-e5-small_linux-x86_64” 作为嵌入模型
  3. 单击 “Next” 按钮

%title插图%num

接下来,我们将通过以下方式配置数据字段:

  1. 从 “Content data” 下拉列表中选择包含相关内容的所有字段(例如 “author_name” 和 “description”)
  2. 保留 “title” 和 “Vector fields” 的默认值

%title插图%num

在下一个屏幕上,检查你的 data source 设置,然后单击 “Save and close” 按钮,你就可以开始聊天了。

%title插图%num

现在你已准备好与你的数据聊天。 这就是语义搜索真正发挥作用的地方。 我能够提出一个初始问题,然后使用聊天历史记录的语义和上下文,能够以自然语言询问我的数据的后续问题。

%title插图%num

最棒的是我可以看到与弹出窗口中提供的上下文一致的引文。

%title插图%num

接下来该怎么做?

与索引对话只是你能做的众多强大功能之一。在 Azure OpenAI On Your Data 集成之外,一旦你将数据导入 Elasticsearch,还有许多其他尝试,例如使用我们支持的众多第三方嵌入模型之一来部署文本嵌入模型

可以尝试以下内容:

  1. 使用由 Elastic 训练的稀疏向量检索模型 ELSER
  2. 使用 Cohere、HuggingFace 或 OpenAI 的嵌入模型设置语义搜索
  3. 一般来说,任何支持架构的训练模型都可以使用 eland 部署到 Elasticsearch 中。

Elasticsearch 还提供了以下功能:

  1. 使用搜索模板,这是一种存储的搜索,你可以使用不同的变量来运行搜索,而不需要向用户公开 Elasticsearch 的查询语法。搜索模板允许你在不修改应用程序代码的情况下更改搜索。
  2. 使用混合搜索,将词法(BM25)搜索与近似最近邻(kNN)搜索的强大功能结合起来。
  3. 使用学习排序(Learn To Rank)或查询重评分阶段重新排序,以及使用 Cohere 的重新排序 API

并非所有搜索用例都是语义搜索用例。如果词法搜索(BM25)更适合你的搜索用例,Elasticsearch 提供了几个功能来帮助你获得最相关的搜索结果:

  1. 同义词可以帮助你找到包含类似词语的文档,纠正常见拼写错误,或使特定领域的语言更易于用户理解。你可以使用 synonym API 在内部系统索引中定义和管理同义词,或将相关同义词分组到 “同义词集” 中。
  2. Query Rules 允许为符合指定条件的查询自定义搜索结果。这可以更好地控制结果,例如确保符合定义条件的推广文档出现在结果列表的顶部。

准备好自己尝试了吗?开始免费试用。 Elasticsearch 还集成了 LangChain、Cohere 等工具。加入我们的高级语义搜索网络研讨会,构建你的下一代 AI 应用程序!

原文:Azure OpenAI On Your Data: How to use Elasticsearch as the Vector Database — Elastic Search Labs

文章来源于互联网:使用 Elasticsearch 作为 Azure OpenAI On Your Data 的向量数据库