PostgreSQL作為矢量數據庫的入門和擴展實踐
譯文譯者 | 李睿
審校 | 重樓
PostgreSQL擁有豐富的擴展和解決方案生態(tài)系統(tǒng),使開發(fā)人員能夠將數據庫用于通用人工智能應用程序。這一指南將引導他們完成使用PostgreSQL作為矢量數據庫構建生成式人工智能應用程序所需的步驟。
首先從Pgvector擴展開始,它使Postgres具有特定于矢量數據庫的功能。然后,將回顧在PostgreSQL上運行的人工智能應用程序如何提高性能和可擴展性的方法。最后,將使用一個功能齊全的生成式人工智能應用程序,向那些前往舊金山的旅客推薦Airbnb的住宿房源。
Airbnb推薦服務
示例應用程序是一項住宿推薦服務。想象一下,如果旅客計劃去舊金山旅游,并希望住在金門大橋附近的一個靠譜社區(qū)。當他們進入Airbnb推薦服務,輸入提示,應用程序就會推薦三個最相關的住宿選擇。
該應用程序支持兩種不同的模式:
- OpenAI聊天模式:在這一模式下,Node.js后端利用OpenAI聊天通過API和GPT-4模型根據用戶的輸入生成住宿推薦。雖然這一模式不是本指南的重點,但可以進行嘗試。
- Postgres嵌入模式:最初,后端使用OpenAI嵌入API將用戶的提示轉換為嵌入(文本數據的矢量化表示)。接下來,該應用程序在Postgres或YugabyteDB(分布式PostgreSQL)中進行相似性搜索,以找到與用戶提示匹配的Airbnb屬性。Postgres利用Pgvector擴展在數據庫中進行相似性搜索。本指南將深入研究這個特定模式在應用程序中的實現。
先決條件
- 可訪問嵌入模型的OpenAI訂閱。
- 最新的Node.js版本
- 最新版本的Docker
使用Pgvector啟動PostgreSQL
Pgvector擴展將向量數據庫的所有基本功能添加到Postgres中。它允許存儲和處理具有數千個維度的向量,計算向量化數據之間的歐幾里得和余弦距離,并執(zhí)行精確和近似的最近鄰搜索。
1.在Docker中用Pgvector啟動一個Postgres實例:
Shell
docker run --name postgresql \
-e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=password \
-p 5432:5432 \
-d ankane/pgvector:latest
2.連接到數據庫容器并打開一個psql會話:
Shell
docker exec -it postgresql psql -h 127.0.0.1 -p 5432 -U postgres
3.啟用Pgvector擴展:
SQL
create extension vector;
4.確認矢量存在于擴展列表中:SQL
1 select * from pg_extension;
oid | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
-------+---------+----------+--------------+----------------+------------+-----------+--------------
13561 | plpgsql | 10 | 11 | f | 1.0 | |
16388 | vector | 10 | 2200 | t | 0.5.1 | |
(2 rows)
加載Airbnb數據集
該應用程序使用了Airbnb的數據集,該數據集包含舊金山7500多處待租房產。每個列表提供詳細的屬性描述,包括房間數量、設施類型、位置和其他功能。這些信息非常適合針對用戶提示進行相似性搜索。
按照下面的步驟將數據集加載到已啟動的Postgres實例中:
1.克隆應用程序存儲庫:
Shell
git clone https://github.com/YugabyteDB-Samples/openai-pgvector-lodging-service.git
2.將Airbnb模式文件復制到Postgres容器中(將{app_dir}替換為應用程序目錄的完整路徑):
Shell
docker cp {app_dir}/sql/airbnb_listings.sql postgresql:/home/airbnb_listings.sql
3.從下面的Google Drive位置下載包含Airbnb數據的文件。該文件的大小為174MB,包含了使用OpenAI嵌入模型為每個Airbnb屬性描述生成的嵌入。
4.將數據集復制到Postgres容器(將{data_file_dir}替換為應用程序目錄的完整路徑)。
Shell
docker cp {data_file_dir}/airbnb_listings_with_embeddings.csv postgresql:/home/airbnb_listings_with_embeddings.csv
5.創(chuàng)建Airbnb架構并將數據加載到數據庫中:
Shell
# Create schema
docker exec -it postgresql \
psql -h 127.0.0.1 -p 5432 -U postgres \
-a -q -f /home/airbnb_listings.sql
# Load data
docker exec -it postgresql \
psql -h 127.0.0.1 -p 5432 -U postgres \
-c "\copy airbnb_listing from /home/airbnb_listings_with_embeddings.csv with DELIMITER '^' CSV;"
Airbnb的每個嵌入都是一個1536維的浮點數數組。這是Airbnb房產描述的數字/數學表示。
Shell
docker exec -it postgresql \
psql -h 127.0.0.1 -p 5432 -U postgres \
-c "\x on" \
-c "select name, description, description_embedding from airbnb_listing limit 1"
# Truncated output
name | Monthly Piravte Room-Shared Bath near Downtown !3
description | In the center of the city in a very vibrant neighborhood. Great access to other parts of the city with all modes of public transportation steps away Like the general theme of San Francisco, our neighborhood is a melting pot of different people with different lifestyles ranging from homeless people to CEO''s
description_embedding | [0.0064848186,-0.0030366974,-0.015895316,-0.015803888,-0.02674906,-0.0083198985,-0.0063770646,0.010318241,-0.011003947,-0.037981577,-0.008783566,-0.0005710134,-0.0028015983,-0.011519859,-0.02011404,-0.02023159,0.03325347,-0.017488765,-0.014902675,-0.006527267,-0.027820067,0.010076611,-0.019069154,-0.03239144,-0.013243919,0.02170749,0.011421901,-0.0044701495,-0.0005861153,-0.0064978795,-0.0006775427,-0.018951604,-0.027689457,-0.00033081227,0.0034317947,0.0098349815,0.0034775084,-0.016835712,-0.0013787586,-0.0041632145,-0.0058219694,-0.020584237,-0.007386032,0.012486378,0.012473317,0.005815439,-0.010990886,-0.015111651,-0.023366245,0.019069154,0.017828353,0.030249426,-0.04315376,-0.01790672,0.0047444315,-0.0053419755,-0.02195565,-0.0057338076,-0.02576948,-0.009769676,-0.016914079,-0.0035232222,...
嵌入是用OpenAI的text- embeddings -ada-002模型生成的。如果需要使用不同的模型,那么:
- 更新{app_dir}/backend/embeddings_generator.js和{app_dir}/backend/postgres_embeddings_service.jsfile中的模型
- 通過node embeddings_generator.js命令啟動生成器來重新生成嵌入。
查找最相關的Airbnb住宿房源
至此,Postgres已經準備好向用戶推薦最相關的Airbnb住宿房源。該應用程序可以通過比較用戶的提示嵌入與Airbnb描述的嵌入來獲得這些推薦。
首先,啟動Airbnb推薦服務的一個實例:
1.使用OpenAI API密鑰更新{app_dir}/application.properties.ini:
Shell
1 OPENAI_API_KEY=<your key>
2.啟動Node.js后端:
Shell
cd {app_dir}
npm i
cd backend
npm start
3.啟動React前端:
Shell
cd {app_dir}/frontend
npm i
npm start
應用程序用戶界面(UI)應在默認瀏覽器中自動打開。否則,請在地址打開http://localhost:300 。
現在,從應用程序用戶界面(UI)中選擇Postgres Embeddings模式,并要求應用程序推薦一些與以下提示最相關的Airbnb住宿房源:
Shell
I'm looking for an apartment near the Golden Gate Bridge with a nice view of the Bay.
該服務將推薦三種住宿選擇:
在內部,應用程序執(zhí)行以下步驟來生成推薦(詳細信息請參見{app_dir}/backend/postgres_embeddings_service.js):
1.應用程序使用OpenAI Embeddings模型(text- Embeddings -ada-002)生成用戶提示的矢量化表示:
JavaScript
const embeddingResp = await this.#openai.embeddings.create(
{model: "text-embedding-ada-002",
input: prompt});
2.該應用程序使用生成的向量來檢索存儲在Postgres中的最相關的Airbnb屬性:
JavaScript
const res = await this.#client.query(
"SELECT name, description, price, 1 - (description_embedding <=> $1) as similarity " +
"FROM airbnb_listing WHERE 1 - (description_embedding <=> $1) > $2 ORDER BY description_embedding <=> $1 LIMIT $3",
['[' + embeddingResp.data[0].embedding + ']', matchThreshold, matchCnt]);
相似度計算為存儲在description_embedding列中的嵌入與用戶提示向量之間的余弦距離。
3.建議的Airbnb屬性以JSON格式返回到React前端:
JavaScript
let places = [];
for (let i = 0; i < res.rows.length; i++) {
const row = res.rows[i];
places.push({
"name": row.name,
"description": row.description,
"price": row.price,
"similarity": row.similarity });
}
return places;
擴展方式
目前,Postgres存儲了超過7500處Airbnb住宅房源。通過比較用戶提示和Airbnb描述的嵌入,數據庫執(zhí)行精確的最近鄰搜索只需要幾毫秒的時間。
然而,精確的最近鄰搜索(全表掃描)有其局限性。隨著數據集的增長,Postgres在多維向量上執(zhí)行相似性搜索將花費更長的時間。
為了在不斷增長的數據量和流量中保持Postgres的性能和可擴展性,可以為向量化數據使用專門的索引和/或使用分布式版本的Postgres水平擴展存儲和計算資源。
Pgvector擴展支持多種索引類型,包括性能最好的HNSW索引(Hierarchical Navigable Small World)。該索引對向量化數據執(zhí)行近似最近鄰搜索(ANN),允許數據庫即使使用大數據量也能保持低且可預測的延遲。然而,由于搜索是近似的,搜索的召回可能不是100%相關/準確的,因為索引只遍歷數據的一個子集。
例如,以下是如何在Postgres中為Airbnb嵌入創(chuàng)建HNSW索引:
SQL
CREATE INDEX ON airbnb_listing
USING hnsw (description_embedding vector_cosine_ops)
WITH (m = 4, ef_construction = 10);
要想更深入地了解HNSW指數是如何構建的,以及如何在Airbnb數據上執(zhí)行人工神經網絡搜索,請查看以下視頻:
使用分布式PostgreSQL,當單個數據庫服務器的容量不再足夠時,可以輕松地擴展數據庫存儲和計算資源。雖然PostgreSQL最初是為單服務器部署而設計的,但它的生態(tài)系統(tǒng)包含了一些擴展和解決方案,使它能夠在分布式配置中運行。其中一個解決方案是YugabyteDB,它是一個分布式SQL數據庫,擴展了Postgres在分布式環(huán)境中的功能。
YugabyteDB自2.19.2版本起支持Pgvector擴展。它將數據和嵌入分布在一組節(jié)點上,促進了大規(guī)模的相似性搜索。因此,如果希望Airbnb服務在Postgres的分布式版本上運行:
1.部署一個多節(jié)點YugabyteDB集群。
2.更新{app_dir}/application.properties.ini文件中的數據庫連接設置:
Properties files
# Configuration for a locally running YugabyteDB instance with defaults.
DATABASE_HOST=localhost
DATABASE_PORT=5433
DATABASE_NAME=yugabyte
DATABASE_USER=yugabyte
DATABASE_PASSWORD=yugabyte
3.從頭加載數據(或者使用YugabyteDB Voyager從正在運行的Postgres實例中遷移數據)并重新啟動應用程序。不需要其他代碼級別的更改,因為YugabyteDB與Postgres具有功能和運行時兼容性。
觀看以下的視頻,了解Airbnb推薦服務如何在分布式Postgres版本上運行:
使用Postgres構建可擴展的人工智能應用程序很有趣,人們可以了解更多關于Postgres作為矢量數據庫的知識。
原文標題:PostgreSQL as a Vector Database: Getting Started and Scaling,作者:Denis Magda