
以前只能使用第三方工具,
現在終於可以在Firestore中進行全文搜索了!!
這次介紹的是基於向量搜索的全文搜索實施步驟。
前提
此次介紹的功能是預覽版。
隨著正式發佈,下列代碼可能無法執行。
參考:向量嵌入搜索:https://firebase.google.com/docs/firestore/vector-search
此次使用的Function和Vertex AI需要支付費用。
使用前請先確認。
參考:Vertex AI:https://cloud.google.com/vertex-ai/generative-ai/pricing?hl=zh
大致步驟
關於向量搜索會另寫文章介紹,
這次將使用Google提供的「Vertex AI」來計算用於向量搜索的向量。
此外,向量搜索目前只能使用Python或JavaScript(Node.js),
因此這次使用Google Cloud Function來進行搜索。
因此,為了進行搜索需要準備以下內容。
- 創建Google Cloud Function
- 配置Vertex AI
- 獲取向量
- 創建索引
- 在Firestore中實施向量搜索的代碼
詳細步驟如下說明。
創建Google Cloud Function
這次創建的Cloud Functions環境如下。
- 2nd gen(第二代)
- https觸發器
- Python3.12
還配置了以下運行時環境變數。
名稱:GOOGLE_CLOUD_PROJECT
值:<專案ID>(注意不是專案名稱)
因為Vertex AI需要與Cloud Run綁定,所以使用了創建GCF時會創建Cloud Run的
2nd gen(第二代)。
配置Google提供的Vertex AI
將Function的Cloud Run與Vertex AI綁定。
(參考官方文檔:https://cloud.google.com/run/docs/integrate/vertex-ai?authuser=3&hl=zh)
這裡也列出了步驟供參考。
- 點擊右側「Powered by Cloud Run」下的鏈接,進入Cloud Run
- 點擊「整合」標籤
- 點擊「添加整合」
- 點擊「Vertex AI – 生成 AI」,設置任意名稱,然後點擊「提交」
※但名稱需要符合一定規則,否則會報錯。
如果沒有特別要求,保持默認即可。 - 如果要求添加權限等,請進行批准
使用向量搜索的向量計算
這次是以擁有者權限進行的,所以沒有添加權限等操作,
在應用開發時需要為執行Function的帳號分配Vertex AI或Firestore的權限。
以下是使用Vertex AI計算向量並將數據存入Firestore的代碼。
(參考官方文檔:https://firebase.google.com/docs/firestore/vector-search)
functions-framework==3.*
google-cloud-firestore
google-cloud-aiplatform
import functions_framework
import os
# firestore
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector
# Vertex AI
import vertexai
from vertexai.language_models import TextEmbeddingModel
# 專案名稱(從環境變數中獲取)
MY_PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT")
# 從傳遞的字符串中計算向量值
def text_embedding(text: str) -> list:
# 設置location為各自的地區
vertexai.init(project=MY_PROJECT_ID, location="asia-northeast1")
# 使用最新的向量計算AI「textembedding-gecko@003」
model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")
embeddings = model.get_embeddings([text])
for embedding in embeddings:
vector = embedding.values
return Vector(vector)
# 主處理
# (函數名可隨意命名)
@functions_framework.http
def hello_http(request):
# 從請求中獲取文章摘要(description)
request_json = request.get_json(silent=True)
request_args = request.args
if request_json and 'description' in request_json:
description = request_json['description']
elif request_args and 'description' in request_args:
description = request_args['description']
else:
description = 'World'
# 初始化Firestore客戶端
firestore_client = firestore.Client(project=MY_PROJECT_ID)
# 參考集合(集合名稱可隨意設置(如果集合不存在請提前創建))
collection = firestore_client.collection("article_collection")
# 計算embedding
embedding_vector = text_embedding(description)
# 準備要添加到Firestore的文檔
doc = {
"description": description,
"embedding_field": embedding_vector
}
# 添加文檔
collection.add(doc)
return 'OK!'
這次比較簡單,直接在終端執行CLI測試命令來確認操作。
curl -m 70 -X POST https://asia-northeast1-python-tool-001.cloudfunctions.net/vector_chenge \
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" \
-d '{ "description": "<任意字符串>"}'
如果執行成功,應該會在Firestore中看到如下數據。

為向量搜索創建索引
向量搜索需要創建索引。
這次在控制台執行以下命令創建索引。
(參考官方文檔:https://firebase.google.com/docs/firestore/vector-search)
gcloud alpha firestore indexes composite create \
--collection-group=article_collection \
--query-scope=COLLECTION \
--field-config field-path=embedding_field,vector-config='{"dimension":"768", "flat": "{}"}' \
--database=<數據庫ID>
- collection-group:創建索引的集合名稱
- query-scope:這裡不太清楚,但似乎是創建索引的範圍
可以指定多個集合(集合組)。 - field-path:存放向量的字段名稱
- vector-config:設置向量的維度數(這次是768維)
- database:指定目標數據庫的ID。如果是default,可以不指定
執行後,應該會在Firestore中看到如下索引。

在Firestore中實施向量搜索的代碼
數據準備完成後,進行實際搜索。
這次準備了我的博客文章摘要作為搜索對象數據。
全文展示會很長,這裡省略部分內容。
No. | 標題 |
---|---|
1 | freezed.dart無法生成時的應對方法 使用freezed設計不可變類時, 在終端執行「… |
2 | 什麼是Flutter的pubspec.yaml?介紹其意義和寫法!! YAML是YAML Ain’t Markup Language的簡稱, 用來簡潔地表示數據… |
3 | 應用開發中經常聽到的MVVM是什麼? MVVM(Model-View-ViewModel)是, 將應用邏輯和UI(用戶界面)分離, 以提高開發效率和可維護性… |
4 | 什麼是Flutter??解釋Flutter的概述 關於「Flutter」,有「在開發移動應用時很方便!」的認識 也許你知道,但為什麼方便,為什麼受歡迎呢? |
5 | 什麼是Riverpod?介紹Flutter最主流的狀態管理!! 以前介紹過的「StatefulWidget」也是一種狀態管理功能之一, 當實現具有多個屏幕和功能的應用時,管理… |
執行的代碼如下。
import functions_framework
import os
# firestore
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
# Vertex AI
import vertexai
from vertexai.language_models import TextEmbeddingModel
# 專案名稱(從環境變數中獲取)
MY_PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT")
# 從傳遞的字符串中計算向量值
def text_embedding(text: str) -> list:
# 設置location為各自的地區
vertexai.init(project=MY_PROJECT_ID, location="asia-northeast1")
# 使用最新的向量計算AI「textembedding-gecko@003」
model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")
embeddings = model.get_embeddings([text])
for embedding in embeddings:
vector = embedding.values
return Vector(vector)
# 主處理
# (函數名可隨意命名)
@functions_framework.http
def hello_http(request):
# 從請求中獲取文章摘要(description)
request_json = request.get_json(silent=True)
request_args = request.args
if request_json and 'target' in request_json:
target = request_json['target']
elif request_args and 'target' in request_args:
target = request_args['target']
else:
target = 'World'
# 初始化Firestore客戶端
firestore_client = firestore.Client(project=MY_PROJECT_ID)
# 參考集合
collection = firestore_client.collection("article_collection")
# 計算embedding
embedding_vector = text_embedding(target)
# 實施向量搜索
docs = collection.find_nearest(
vector_field="embedding_field",
query_vector=embedding_vector,
distance_measure=DistanceMeasure.COSINE,
limit=3
).get()
# 輸出為表格形式(這裡是字符串形式)
output = "Description \n"
output += "-" * 50 + "\n"
# 輸出向量搜索獲得的文檔內容
for doc in docs:
doc_data = doc.to_dict()
description = doc_data.get("description", "No description")
# 將文檔內容添加到字符串
output += f"{description[:100]} \n"
return output
這次也在終端執行CLI測試命令來確認操作。
嘗試搜索「Riverpodについて」!
curl -m 70 -X POST https://asia-northeast1-python-tool-001.cloudfunctions.net/vector_search \
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" \
-d '{
"target": &
quot;Riverpodについて"
}'
執行結果
Description
--------------------------------------------------
什麼是Riverpod?介紹Flutter最主流的狀態管理!! 以前介紹過的「StatefulWidget」也是一種狀態管理功能之一, 當實現具有多個屏幕和功能的應用時,管理
什麼是Flutter??解釋Flutter的概述 關於「Flutter」,有「在開發移動應用時很方便!」的認識 也許你知道,但為什麼方便,為什麼受歡迎呢?
應用開發中經常聽到的MVVM是什麼? MVVM(Model-View-ViewModel)是, 將應用邏輯和UI(用戶界面)分離, 以提高開發效率和可維護性
雖然沒有進行排序,但第一條結果是Riverpod的文章!!
這次的數據無法判斷第二條和第三條是否選得較近。
最後
還需要增加數據量來更好地檢驗搜索精度。
向量數據大小約為768維,每個float為4字節,因此768✕4≒3KB。
文檔限制為1MB,所以感覺有點大。
雖然目前是預覽版,但Firestore可以進行全文搜索確實是個好消息。
期待今後的進展。