Vespa ai 筆記 (一)
Vespa ai 筆記 (一)
Vespa 是什麼
一般講到vespa 通常第一個聯想到的往往是某個機車品牌XD,然而除了機車品牌外它同時也是一個開源的搜索引擎,Vespa 由 Yahoo! ( verizon media ) 於 2017年9月發布, Vespa 用於對海量數據集進行低延遲計算的引擎,它負責存儲和索引數據資料。同時 Vespa 中也提供了: Indexing, Searching, Ranking, Grouping,等等許多自定義的擴展功能。
來看看官方的描述:
第一次看到是不是會有種不明覺厲的感覺XD
而也因為這些特性我們常常利用vespa 來建立:
- 搜尋引擎
- 個人化推薦系統
- 需要 Realtime 數據顯示的地圖,標籤,圖形…等等
而 Vespa 團隊因為近期因為 CORD-19 (新型冠壯肺炎)的快速傳染,利用Allen Institute for AI 所釋出的公開資料集,建立了新型冠壯病毒的搜尋網站,而該專案也是完全開源的(點這裡查看)。
Vespa 的索引概念以及運作原理
Vespa 的主要架構圖如下
主要可以分為三塊
- Stateless Container Cluster
- Content Cluster
- Admin and config clusters
Stateless Container Cluster
為架構圖中藍色的部份,主要負責 Document 的 get, put, update, remove 等操作,當有外部的 request 打進來時,Container cluster 會自動將操作送到對應的 content node 中進行。自定義的排序方法、文件處理、其他功能也在此 cluster 中進行 。
Content Cluster
相較於前者,Content Cluster 負責的業務則相對簡單,負責資料的儲存,會將同一份資料複製到多個節點上,以及執行從 Container Cluster 所要求的操作,當所有 Cluster 中對應的節點執行完操作後,content Cluster 會自動匯總結果。
而該 cluster 會自動平衡節點中的數據量,並且維持 Redundancy 已提高容錯性,針對壞掉的節點自動進行故障轉移,保證高可用行並自動恢復。
Admin and config clusters
除了上述兩種外還有第三種主要負責一些節點設定等等。
利用 Vespa 動手實做一個簡單的搜尋引擎吧!!
介紹
利用 WorldPress 的資料集建立一個部落格文章推薦系統,實做用戶文章搜尋,以及個人文章推薦的功能,而該文章由Vespa Team 所發布可以點這裡查看原文。
Prerequisites
- Docker
- Git
- OS : macOS or Linux(Ubuntu, CentOS …..)
- Architecture: x86_64
- Minimum 6GB memory dedicated to Docker (the default is 2GB on Macs) - 10G for monitoring section.
Dataset
Post 的基本屬性
| Column | Description |
| —————– |:———————– |
| post_id | unique numerical id identifying the blog post |
| date_gmt | string representing date of blog post creation in GMT format yyyy-mm-dd hh:mm:ss |
| author | unique numerical id identifying the author of the blog post |
| url | blog post URL|
| title | blog post title|
| blog | unique numerical id identifying the blog that the blog post belongs to|
| tags | array of strings representing the tags of the blog posts|
| content | body text of the blog post, in html format|
| categories | array of strings representing the categories the blog post was assigned to|
Requirements
在開始前必須要先建立環境,利用官方所提供的 docker image 可以快速的把環境建好~
建立 & 切換 工作目錄
1 | $ mkdir blog |
建立 Docker 環境
1 | $ docker run -m 10G --detach --name vespa --hostname vespa-tutorial \ |
若上述步驟遇到 docker memory limit 解法參考 link
確認 server 建立成功,會得到 200 OK 的 response
1 | $ docker exec vespa bash -c 'curl -s --head http://localhost:19071/ApplicationStatus' |
Clone Git Repo ,會利用當中的 script 產生 data
1 | $ git clone --depth 1 https://github.com/vespa-engine/sample-apps.git |
下載Feeding 時所需的資料點這裡
至此恭喜您已經完成所有的環境建立步驟~
加入設定檔
加入必要的設定檔
在剛剛空的資料夾中建立對應資料夾 application
1 | $ mkdir application |
在 application 目錄中建立 services.xml,用來定義需要多少 server 的基本配置。
1 | <?xml version='1.0' encoding='UTF-8'?> |
用以定義上述架構圖中的 container cluster 設定 query endpoint , 預設為 8080 port 設定 Feeding 文件的 endpoint 設定該 cluster 中需要多少節點 設定 content cluster 設定需要多少份複製文件以供節點錯誤時進行自動回復 指定 node 中的 document schema (sd 檔) 設定 cluster 中的 node
在 application 目錄中建立 hosts.xml,由於我們使用docker 在 local host 建立,只需要定義為如下即可。
1 | <?xml version="1.0" encoding="utf-8" ?> |
建立 application 目錄中建立 blog 要被搜尋的文件的 blog_post.sd , 路徑 application/schemas/blog_post.sd
1 | schema blog_post { |
當中 indexing 設定了vespa 會如何 indexing 該欄位
- index : 對該欄位界建立 index 供搜尋時使用
- attribute : 會將該欄位存在 memory 中,供排序、搜尋、合併時使用
- summary : 定義使否出現在 summary 中,搜尋的結果是否會將該欄位顯示
建立完成後application 目錄下應該會長這樣
部屬應用到本機端
1 | $ docker exec vespa bash -c '/opt/vespa/bin/vespa-deploy prepare /app/application && \ |
接著去打 http://localhost:8080/ApplicationStatus 就能看到一些基本資訊,說明應用已經成功部屬。
Feeding Data
接著我們將必要的資料 Feeding 到搜尋引擎中。
將剛剛下載的文檔解壓縮
擷取前10000 筆資料(也可以跳過這步驟使用整個dataset XD) ,並利用script 轉成 對應的 JSON 格式,以降低處理時間。
1 | $ head -10000 trainPosts.json > trainPostsSmall.json |
利用 Vespa Team 提供的 JAVA Feeding API 將資料打進 Vespa 搜尋引擎中
1 | $ docker exec vespa bash -c 'java -jar /opt/vespa/lib/jars/vespa-http-client-jar-with-dependencies.jar \ |
利用 Metrics API 確認 feeding 結果,若 Feeding 成功則會看見對應的 feeding 筆數。
1 | $ curl -s "http://localhost:19092/metrics/v1/values" | tr "," "\n" | grep content.proton.documentdb.documents.active |
現在我們可以用對應的 Doc ID 去要資料。
1 | $ curl -s 'http://localhost:8080/document/v1/blog-search/blog_post/docid/507823' | json_pp |
Query
用自訂的 query 去搜尋引擎拉東西
通常 vespa 利用 HTTP GET, HTTP POST 的 request 會長得像下面格式。
1 | <host:port>/<search>?<yql=value1>&<param2=value2>... |
我們可以用以下兩種形式的Query 去要資料,而使用的為YQL 的Query 語法 。
1 | curl -s -H "Content-Type: application/json" --data '{"yql" : "select * from sources * where default contains \"music\";"}' \ |
1 | $ curl -s 'http://localhost:8080/search/?yql=select+*+from+sources+*+where+default+contains+%22music%22%3B' | python -m json.tool |
以上兩種都是利用搜尋 trump 出現在 default 欄位中的 item, 而這邊的 defaut 指的是我們在 sd 中所建立的 field set : default,當中包含了 title, content 兩個欄位,因此會對這兩個欄位進行 filter。
自定義排序功能
Relevance and Ranking,我們可以藉由自定義排功能,根據不同欄位計算相對應的權重,計算文章的相關性,用以實現自己想要的排序結果。
首先我們在先前定義好的SD 檔中新增 popularity 欄位,以及新的排序公式
1 | field popularity type double { |
1 | rank-profile post_popularity inherits default { |
我們新增了一條公式,繼承原本的rank-profile,並且覆寫掉第一階段的排序,將原本計算的分數加上 10 * popularity 欄位的值作為新的排序依據。
將新的應用部屬
1 | $ docker exec vespa bash -c '/opt/vespa/bin/vespa-deploy prepare /app/application && \ |
Feeding 含有popularity 的文件
1 | $ python sample-apps/blog-tutorial-shared/src/python/parse.py \ |
完成後我們再進行 curl ,比較新舊query profile 的差異
原本的返回結果
1 | curl -s -H "Content-Type: application/json" --data '{"yql" : "select title, content, popularity from sources * where default contains \"music\";"}' http://localhost:8080/search/ | json_pp |
使用新的popularity rank profile 的結果
1 | curl -s -H "Content-Type: application/json" --data '{"yql" : "select * from sources * where default contains \"music\";", "ranking" : "post_popularity"}' \ |
我們可以發現套用了post_popularity 的 rank-profile 排序變成給予popularity 的 item 較高排序權重,即便 content 跟 title 中都沒有出現相對應的搜尋文字。
左:default rank profile 右:使用popularity rank profile
至此我們已經完成了
- 環境搭建
- Vespa 引擎設定
- 部屬應用
- Feeding 資料
- 利用 YQL 進行簡單的搜尋
- 自訂義排序
下篇文章會繼續實做個人化的推薦系統~
結論
沒意外的話應該會將剩餘的內容切分到下幾篇文章 XD,本身對 Vespa 的用法也只是摸到皮毛,當中內部許多功能的實現方法也還沒有深入的研究,一樣還在持續的學習中,若文章中有錯誤的地方希望能鞭小力點XD,現今開源引擎較廣為人知的是 Elasticsearch, SOLR , 然而 Vespa 的出現也提供了開發者一個新的選擇 ~
References
Vespa ai 筆記 (一)