簡單上手向量資料庫,打造 RAG 應用: Weaviate DB 101

簡單上手向量資料庫,打造 RAG 應用: Weaviate DB 101

簡單上手向量資料庫,打造 RAG 應用: Weaviate DB 101鄭元傑 Yuanchieh14 min read·Jul 26, 2023--

Share

當我們希望打造一個基於語意相似的文字搜尋時,一般的作法是將文字透過 AI model 轉成 embeddeding vector,透過計算 vector distance (cosine distancing) 找出距離最相近的文字 kNN (k nearest neighbors),例如OpenAI 的 demo code:Semantic_text_search_using_embeddings

當資料量小的時候,這樣做不會有什麼問題,但仔細看目前的比對方式是把輸入跟資料集的資料每一筆 vector 都做 distance 計算,所以複雜度會是 -O(N),N 是資料集數量,如果資料量一大,這勢必會是造成瓶頸

Vector DB 就是要解決這樣的問題,主要透過

改用 ANN (approximate nearest neighbors) 取代 kNN,用相似度查詢換取執行速度提供 database 功能,包含持久化保存、水平擴展 (sharding)、高可用性、API 封裝等功能Press enter or click to view image in full size目前搜尋市面上有幾個常見的選擇

Pinecone:閉源專案,就先略過不用Milvus:純 vector DB,看起來在基礎建設 (scaling、availability) 等做得比較完整Weaviate:有 module 可以支援 AI model 整合,也支援純 vector DB 使用Chroma:Fireship demo 用Elasticsearch: 8.0 後就有支援 vector search這次 Demo 選擇用 Weaviate,主要是有支援 module 直接整合 AI model,這樣我就不用另外想 embedding vector 該如何產生

Press enter or click to view image in full sizeWeaviate DB 基本介紹Weaviate DB 有以下幾個特色

便利性:module 支援常見的 AI model,包含 transformer、openai 等,透過參數可以直接調整,但有些 AI model 部分需要自己架設 server,Weaviate DB 核心並不包含 AI model,只是會直接透過 interface 調用搜尋與過濾:除了 vector 搜尋外,在文字上會結合 inverted index 增加搜尋的精準度與效率,並提供 filter 可以透過屬性篩選API 接口支援 REST 與 GraphQLScalability:會提供 Sharding 與 High Availability (後者還在開發中)儲存概念以 Class 為管理單位,可以理解成 table 或 collection 的概念,每個 class 有自己 vectorize 的機制、sharding 設定等,例如

{ "class": "string", // The name of the class in string format "description": "string", // A description for your reference "vectorIndexType": "hnsw", // Defaults to hnsw, can be omitted in schema definition since this is the only available type for now "vectorIndexConfig": { ... // Vector index type specific settings, including distance metric }, "vectorizer": "text2vec-contextionary", // Vectorizer to use for data objects added to this class "moduleConfig": { "text2vec-contextionary": { "vectorizeClassName": true // Include the class name in vector calculation (default true) } }, "properties": [ // An array of the properties you are adding, same as a Property Object { "name": "string", // The name of the property "description": "string", // A description for your reference "dataType": [ // The data type of the object as described above. When creating cross-references, a property can have multiple data types, hence the array syntax. "string" ], "moduleConfig": { // Module-specific settings "text2vec-contextionary": { "skip": true, // If true, the whole property will NOT be included in vectorization. Default is false, meaning that the object will be NOT be skipped. "vectorizePropertyName": true, // Whether the name of the property is used in the calculation for the vector position of data objects. Default false. } }, "indexInverted": true // Optional, default is true. By default each property is fully indexed both for full-text, as well as vector search. You can ignore properties in searches by explicitly setting index to false. } ], "invertedIndexConfig": { ... }, "shardingConfig": { ... // Optional, controls behavior of class in a multi-node setting, see section below }}每個 Class 內包含多個 Object 以 json 格式儲存,Object 內的屬性 (Property) 支援 多種格式,額外有提供地理位置、日期、電話號碼(有點不解?!),其中地理位置在查詢上還支援方圓內的篩選

Class schema 是靜態的,如果要增減欄位需要透過 API 修改,而不像某些 NoSQL 是動態寫入的

物理儲存以 Shard 為單位一個 Class 在物理儲存上由多個 Shard 分散儲存,每個 Shard 建立時會同時包含 vector index / object store / inverted index 三個 index,其中 vecotr index 目前是用 HNSW,其餘兩個是用 LSMTree 儲存

Demo — 打造簡易的文字查詢程式碼在 sj82516/weaviate-db-demo ,在本地端啟動 Weaviate DB 並做簡易的文字查詢

透過 docker-compose 啟動這邊我們只做文字搜尋的部分,選用 transformer 當作 AI model,可以自行替換 不同的 modules

version: '3.4'services: weaviate: image: semitechnologies/weaviate:1.18.3 ports: - "8080:8080" environment: QUERY_DEFAULTS_LIMIT: 20 AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true' PERSISTENCE_DATA_PATH: "./data" DEFAULT_VECTORIZER_MODULE: text2vec-transformers ENABLE_MODULES: text2vec-transformers # 選擇的 text 向量化方式 TRANSFORMERS_INFERENCE_API: http://t2v-transformers:8080 CLUSTER_HOSTNAME: 'node1' t2v-transformers: image: semitechnologies/transformers-inference:sentence-transformers-multi-qa-MiniLM-L6-cos-v1 environment: ENABLE_CUDA: 0建立 Class 與匯入資料Class schema 可以主動宣告,或是讓 Weaviate DB 自動幫忙建立 (有點像 Elasticsearch),這邊建立了一個 Class 並指定 module 用 text-transformer

client.Schema().ClassCreator().WithClass(&models.Class{ Class: className, Description: "all books I have", Vectorizer: "text2vec-transformers", ModuleConfig: map[string]interface{}{ "text2vec-transformers": map[string]interface{}{}, }, Properties: []*models.Property{ { Name: "title", DataType: []string{"text"}, }, },})匯入資料可以批次匯入

objects := []*models.Object{ { Class: className, Properties: map[string]interface{}{ "title": "Hello World Blue", "type": "program", }, }, { Class: className, Properties: map[string]interface{}{ "title": "Hello World Red", "type": "program", }, }, { Class: className, Properties: map[string]interface{}{ "title": "Hello World Yellow", "type": "science", }, },}client.Batch().ObjectsBatcher(). WithObjects(objects...). WithConsistencyLevel(replication.ConsistencyLevel.ALL). Do(context.Background())搜尋與篩選完整查詢有三個部分 搜尋 + 篩選 + 欄位過濾

// 文字搜尋nearText := client.GraphQL().NearTextArgBuilder(). // 搜尋的關鍵字 WithConcepts(concepts). // 讓向量往某個方向靠近 WithMoveTo(&graphql.MoveParameters{ Force: 0.5, Concepts: []string{ "Yellow", }, })// 篩選機制where := filters.Where(). WithPath([]string{"type"}). WithOperator(filters.Equal). WithValueText("program")// 選擇欄位回傳fields := []graphql.Field{ {Name: "title"}, // 額外的欄位,算是 metadata {Name: "_additional", Fields: []graphql.Field{ {Name: "id"}, {Name: "distance"}, }},}// GraphQL Requestresult, err := client.GraphQL().Get(). WithClassName(className). WithNearText(nearText). WithWhere(where). WithFields(fields...). Do(context.Background())if result.Errors != nil { for _, err := range result.Errors { fmt.Println(err.Message) } return}r := result.Data["Get"].(map[string]interface{})[className].([]interface{})jsonbody, err := json.Marshal(r)if err != nil { // do error check fmt.Println(err) return}books := []Book{}if err := json.Unmarshal(jsonbody, &books); err != nil { // do error check fmt.Println(err) return}for _, book := range books { fmt.Println(book)}在 searching 搜尋中,如果是 text Weaviate DB 會用 inverted index 與 vector 搜尋 WithNearText,找出的結果會給出對應的 distance

nearText := client.GraphQL().NearTextArgBuilder(). WithConcepts(concepts). WithMoveTo(&graphql.MoveParameters{ Force: 0.5, Concepts: []string{ "Yellow", }, })concepts 搜尋的文字陣列WithMoveTo 額外指定搜尋要特別接近哪些關鍵字更多參數可參考 Vector search parameters也可以針對屬性做篩選,例如我只要 object 中 type = program 的資料

where := filters.Where(). WithPath([]string{"type"}). WithOperator(filters.Equal). WithValueText("program")搜尋的結果大概是 (Yellow 被篩選掉)

{Hello World Blue {b9f93a34–6cbd-45b3-afc3-f82e9d1d0da8 0.54240143}}{Hello World Red {6575290e-53cc-4ab9–8d39–330e5a47b0d1 0.55338395}}

ANN 演算法:HNSW 介紹Press enter or click to view image in full size主要參考自:https://www.pinecone.io/learn/series/faiss/hnsw/

HNSW (Hierarchical Navigable Small World) 是一種 ANN 演算法,主要是借鏡 probability skip list,透過分層查詢,先從最上層最稀疏的 layer 開始找最相近的鄰居,接著往下一層找該鄰居的最相近鄰居,一直到最底層 (layer 0)

查詢複雜度降至 log (N)

這部分有兩個參數可以注意

efConstruction: 決定每次查詢回傳的鄰居數量,數量越多查詢越精準,但是效率越差maxConnections: 決定每個 point 可以連接的 edge 數量,同樣是數量越多越精準如何決定 point 要插入哪一層這部分便是透過機率所決定,越上層機率越低

Press enter or click to view image in full size結語快速瞭解了一下 Vector DB,未來如果有需要做向量查詢使用上應該會蠻方便的,之後有機會在評估一下 Milvus,看起來基礎建設比 Weaviate DB 更完善、Github 上熱度也更高、也支援更多的 ANN 演算法

相关内容

保卫萝卜3破解版 v4.2.3
beat365官网地址下载

保卫萝卜3破解版 v4.2.3

🕒 07-19 👁️ 9975