หน้านี้แสดงวิธีใช้ Cloud Firestore เพื่อทำการค้นหาเวกเตอร์เพื่อนบ้านใกล้ที่สุด K ตัว (KNN) โดยใช้เทคนิคต่อไปนี้
- จัดเก็บค่าเวกเตอร์
- สร้างและจัดการดัชนีเวกเตอร์ KNN
- สร้างการค้นหา K-nearest-neighbor (KNN) โดยใช้การวัดระยะทางเวกเตอร์ที่รองรับอย่างใดอย่างหนึ่ง
ก่อนเริ่มต้น
ก่อนที่จะจัดเก็บการฝังใน Cloud Firestore คุณต้องสร้างการฝังเวกเตอร์ Cloud Firestore ไม่ได้สร้างการฝัง คุณสามารถใช้บริการอย่าง Agent Platform เพื่อสร้างค่าเวกเตอร์ เช่น การฝังข้อความจากข้อมูล Cloud Firestore จากนั้นคุณสามารถจัดเก็บการฝังเหล่านี้กลับไว้ในเอกสาร Cloud Firestore ได้
ดูข้อมูลเพิ่มเติมเกี่ยวกับการฝังได้ที่การฝังคืออะไร
หากต้องการดูวิธีรับการฝังข้อความด้วย Agent Platform โปรดดูหัวข้อรับการฝังข้อความ
จัดเก็บเวกเตอร์การฝัง
ตัวอย่างต่อไปนี้แสดงวิธีจัดเก็บการฝังเวกเตอร์ใน Cloud Firestore
การดำเนินการเขียนด้วยการฝังเวกเตอร์
ตัวอย่างต่อไปนี้แสดงวิธีจัดเก็บการฝังเวกเตอร์ในเอกสาร Cloud Firestore
Python
Node.js
import { Firestore, FieldValue, } from "@google-cloud/firestore"; const db = new Firestore(); const coll = db.collection('coffee-beans'); await coll.add({ name: "Kahawa coffee beans", description: "Information about the Kahawa coffee beans.", embedding_field: FieldValue.vector([1.0 , 2.0, 3.0]) });
Go
Java
import com.google.cloud.firestore.CollectionReference; import com.google.cloud.firestore.DocumentReference; import com.google.cloud.firestore.FieldValue; import com.google.cloud.firestore.VectorQuery; CollectionReference coll = firestore.collection("coffee-beans"); Map<String, Object> docData = new HashMap<>(); docData.put("name", "Kahawa coffee beans"); docData.put("description", "Information about the Kahawa coffee beans."); docData.put("embedding_field", FieldValue.vector(new double[] {1.0, 2.0, 3.0})); ApiFuture<DocumentReference> future = coll.add(docData); DocumentReference documentReference = future.get();
คำนวณการฝังเวกเตอร์ด้วย Cloud Function
หากต้องการคำนวณและจัดเก็บการฝังเวกเตอร์เมื่อใดก็ตามที่มีการอัปเดตหรือสร้างเอกสาร คุณสามารถตั้งค่า Cloud Function ได้ดังนี้
Python
@functions_framework.cloud_event def store_embedding(cloud_event) -> None: """Triggers by a change to a Firestore document. """ firestore_payload = firestore.DocumentEventData() payload = firestore_payload._pb.ParseFromString(cloud_event.data) collection_id, doc_id = from_payload(payload) # Call a function to calculate the embedding embedding = calculate_embedding(payload) # Update the document doc = firestore_client.collection(collection_id).document(doc_id) doc.set({"embedding_field": embedding}, merge=True)
Node.js
/** * A vector embedding will be computed from the * value of the `content` field. The vector value * will be stored in the `embedding` field. The * field names `content` and `embedding` are arbitrary * field names chosen for this example. */ async function storeEmbedding(event: FirestoreEvent<any>): Promise<void> { // Get the previous value of the document's `content` field. const previousDocumentSnapshot = event.data.before as QueryDocumentSnapshot; const previousContent = previousDocumentSnapshot.get("content"); // Get the current value of the document's `content` field. const currentDocumentSnapshot = event.data.after as QueryDocumentSnapshot; const currentContent = currentDocumentSnapshot.get("content"); // Don't update the embedding if the content field did not change if (previousContent === currentContent) { return; } // Call a function to calculate the embedding for the value // of the `content` field. const embeddingVector = calculateEmbedding(currentContent); // Update the `embedding` field on the document. await currentDocumentSnapshot.ref.update({ embedding: embeddingVector, }); }
Go
// Not yet supported in the Go client library
Java
// Not yet supported in the Java client library
สร้างและจัดการดัชนีเวกเตอร์
ก่อนที่จะทำการค้นหาเพื่อนบ้านใกล้ที่สุดด้วยการฝังเวกเตอร์ คุณต้องสร้างดัชนีที่เกี่ยวข้อง ตัวอย่างต่อไปนี้แสดงวิธีสร้างและจัดการดัชนีเวกเตอร์ด้วย Google Cloud CLI และคอนโซล นอกจากนี้ คุณยังจัดการดัชนีเวกเตอร์ด้วย Firebase CLI และ Terraform ได้ด้วย
สร้างดัชนีเวกเตอร์
คอนโซล Google Cloud
วิธีสร้างดัชนีใหม่ด้วยตนเองจากคอนโซล Google Cloud
- ในคอนโซล Google Cloud ให้ไปที่หน้าฐานข้อมูล
- เลือกฐานข้อมูลที่ต้องการจากรายการฐานข้อมูล
- ในเมนูการนำทาง ให้คลิกดัชนี แล้วคลิกแท็บด้วยตนเอง
- คลิกสร้างดัชนี
หากต้องการจัดทำดัชนีช่องเวกเตอร์สำหรับการค้นหาเวกเตอร์ ให้เลือกสร้างดัชนีเวกเตอร์
-
ป้อนรหัสคอลเล็กชัน ป้อนเส้นทางฟิลด์เวกเตอร์และจำนวนมิติข้อมูลการฝังเวกเตอร์ เพิ่มชื่อของช่องเพิ่มเติมที่ต้องการจัดทำดัชนีและโหมดดัชนีสำหรับแต่ละช่อง
คลิกบันทึกดัชนี
ดัชนีใหม่จะปรากฏในรายการดัชนีที่สร้างด้วยตนเอง และ Cloud Firestore จะเริ่มสร้างดัชนี เมื่อสร้างดัชนีเสร็จแล้ว คุณจะเห็นเครื่องหมายถูกสีเขียวข้างดัชนี
gcloud
ก่อนสร้างดัชนีเวกเตอร์ ให้อัปเกรดเป็น Google Cloud CLI เวอร์ชันล่าสุด โดยทำดังนี้
gcloud components update
หากต้องการสร้างดัชนีเวกเตอร์ ให้ใช้ gcloud firestore indexes composite create:
gcloud firestore indexes composite create \ --collection-group=collection-group \ --query-scope=COLLECTION \ --field-config field-path=vector-field,vector-config='vector-configuration' \ --database=database-id
โดยที่
- collection-group คือรหัสของกลุ่มคอลเล็กชัน
- vector-field คือชื่อของฟิลด์ที่มีการฝังเวกเตอร์
- database-id คือรหัสของฐานข้อมูล
- vector-configuration มีเวกเตอร์
dimensionและประเภทดัชนีdimensionเป็นจำนวนเต็มสูงสุด 2048 ประเภทดัชนีต้องเป็นflatจัดรูปแบบการกำหนดค่าดัชนีดังนี้{"dimension":"DIMENSION", "flat": "{}"}
ตัวอย่างต่อไปนี้จะสร้างดัชนีแบบผสม ซึ่งรวมถึงดัชนีเวกเตอร์สำหรับฟิลด์ vector-field และดัชนีจากน้อยไปมากสำหรับฟิลด์ color คุณสามารถใช้ดัชนีประเภทนี้เพื่อกรองข้อมูลล่วงหน้าก่อนการค้นหาเพื่อนบ้านใกล้ที่สุด
gcloud firestore indexes composite create \ --collection-group=collection-group \ --query-scope=COLLECTION \ --field-config=order=ASCENDING,field-path="color" \ --field-config field-path=vector-field,vector-config='{"dimension":"1024", "flat": "{}"}' \ --database=database-id
แสดงรายการดัชนีเวกเตอร์ทั้งหมด
คอนโซล Google Cloud
- ในคอนโซล Google Cloud ให้ไปที่หน้าฐานข้อมูล
- เลือกฐานข้อมูลที่ต้องการจากรายการฐานข้อมูล
-
ในเมนูการนำทาง ให้คลิกดัชนี แล้วคลิกแท็บด้วยตนเอง
ตารางดัชนีจะแสดงดัชนีทั้งหมดของฐานข้อมูล ดัชนีเวกเตอร์จะมีช่องเวกเตอร์ที่มีไอคอน
gcloud
วิธีแสดงรายการดัชนีทั้งหมดและดึงข้อมูลรหัสดัชนี
gcloud firestore indexes composite list --database=database-id
แทนที่ database-id ด้วยรหัสของฐานข้อมูล
คุณใช้รหัสดัชนีเพื่อดูรายละเอียดเพิ่มเติมเกี่ยวกับดัชนีได้ดังนี้
gcloud firestore indexes composite describe index-id --database=database-id
โดยที่
- index-id คือรหัสของดัชนีที่จะอธิบาย
- database-id คือรหัสของฐานข้อมูล
ลบดัชนีเวกเตอร์
คอนโซล Google Cloud
- ในคอนโซล Google Cloud ให้ไปที่หน้าฐานข้อมูล
- เลือกฐานข้อมูลที่ต้องการจากรายการฐานข้อมูล
-
ในเมนูการนำทาง ให้คลิกดัชนี แล้วคลิกแท็บด้วยตนเอง
- ในรายการดัชนีที่สร้างด้วยตนเอง ให้คลิกปุ่มเพิ่มเติม สำหรับดัชนีที่ต้องการลบ คลิกลบ
- ยืนยันว่าคุณต้องการลบดัชนีนี้โดยคลิกลบดัชนีจากการแจ้งเตือน
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
โดยที่
- index-id คือรหัสของดัชนีที่จะลบ
ใช้
indexes composite listเพื่อดึงรหัสดัชนี - database-id คือรหัสของฐานข้อมูล
สร้างการค้นหาแบบ Nearest Neighbor
คุณสามารถทำการค้นหาความคล้ายคลึงเพื่อค้นหาเวกเตอร์ที่ใกล้เคียงที่สุดของการฝังเวกเตอร์ การค้นหาความคล้ายคลึงต้องใช้ดัชนีเวกเตอร์ หากไม่มีดัชนี Cloud Firestore จะแนะนำดัชนีที่จะสร้างโดยใช้ gcloud CLI
ตัวอย่างต่อไปนี้จะค้นหาเพื่อนบ้านที่ใกล้ที่สุด 10 รายการของเวกเตอร์การค้นหา
Python
Node.js
import { Firestore, FieldValue, VectorQuery, VectorQuerySnapshot, } from "@google-cloud/firestore"; // Requires a single-field vector index const vectorQuery: VectorQuery = coll.findNearest({ vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN' }); const vectorQuerySnapshot: VectorQuerySnapshot = await vectorQuery.get();
Go
Java
import com.google.cloud.firestore.VectorQuery; import com.google.cloud.firestore.VectorQuerySnapshot; VectorQuery vectorQuery = coll.findNearest( "embedding_field", new double[] {3.0, 1.0, 2.0}, /* limit */ 10, VectorQuery.DistanceMeasure.EUCLIDEAN); ApiFuture<VectorQuerySnapshot> future = vectorQuery.get(); VectorQuerySnapshot vectorQuerySnapshot = future.get();
ระยะทางเวกเตอร์
การค้นหาเพื่อนบ้านใกล้ที่สุดรองรับตัวเลือกต่อไปนี้สำหรับระยะห่างเวกเตอร์
EUCLIDEAN: วัดระยะทางEUCLIDEANระหว่างเวกเตอร์ ดูข้อมูลเพิ่มเติมได้ที่ยูคลิดCOSINE: เปรียบเทียบเวกเตอร์ตามมุมระหว่างเวกเตอร์ ซึ่งช่วยให้คุณวัดความคล้ายคลึงที่ไม่ได้อิงตามขนาดเวกเตอร์ได้ เราขอแนะนำให้ใช้DOT_PRODUCTกับเวกเตอร์ที่ปรับมาตรฐานหน่วยแทนระยะทางโคไซน์ ซึ่งเทียบเท่าทางคณิตศาสตร์และมีประสิทธิภาพดีกว่า ดูข้อมูลเพิ่มเติมได้ที่ความคล้ายคลึงของโคไซน์DOT_PRODUCT: คล้ายกับCOSINEแต่ได้รับผลกระทบจากขนาดของเวกเตอร์ ดูข้อมูลเพิ่มเติมได้ที่ผลคูณจุด
เลือกการวัดระยะทาง
คุณสามารถกำหนดการวัดระยะทางที่จะใช้เพื่อค้นหาการวัดระยะทางได้ โดยขึ้นอยู่กับว่าการฝังเวกเตอร์ทั้งหมดได้รับการปรับให้เป็นมาตรฐานหรือไม่ การฝังเวกเตอร์ที่ปรับมาตรฐานแล้วจะมีขนาด (ความยาว) เท่ากับ 1.0 พอดี
นอกจากนี้ หากคุณทราบว่าโมเดลได้รับการฝึกด้วยการวัดระยะทางแบบใด ให้ใช้การวัดระยะทางนั้นเพื่อคำนวณระยะทางระหว่างการฝังเวกเตอร์
ข้อมูลที่ปรับให้เป็นมาตรฐาน
หากคุณมีชุดข้อมูลที่การฝังเวกเตอร์ทั้งหมดได้รับการปรับให้เป็นมาตรฐาน การวัดระยะทางทั้ง 3 แบบจะให้ผลการค้นหาเชิงความหมายเหมือนกัน โดยพื้นฐานแล้ว แม้ว่าการวัดระยะทางแต่ละครั้งจะแสดงผลค่าที่แตกต่างกัน แต่ค่าเหล่านั้นจะจัดเรียงในลักษณะเดียวกัน เมื่อการฝังได้รับการปรับให้เป็นมาตรฐาน DOT_PRODUCT มักจะมีประสิทธิภาพในการคำนวณมากที่สุด แต่ความแตกต่างนั้นไม่มีนัยสำคัญในกรณีส่วนใหญ่ อย่างไรก็ตาม หากแอปพลิเคชันของคุณมีความไวต่อประสิทธิภาพสูง DOT_PRODUCT อาจช่วยปรับแต่งประสิทธิภาพได้
ข้อมูลที่ไม่ได้ปรับให้เป็นมาตรฐาน
หากคุณมีชุดข้อมูลที่ไม่ได้ปรับเวกเตอร์เอ็มเบ็ดดิงให้เป็นมาตรฐาน การใช้ DOT_PRODUCT เป็นการวัดระยะทางจะไม่ถูกต้องตามหลักคณิตศาสตร์ เนื่องจากดอทโปรดักต์ไม่ได้วัดระยะทาง การวัดระยะทาง COSINE หรือ EUCLIDEAN จะให้ผลการค้นหาที่ดีกว่าการวัดระยะทางอื่นๆ ทั้งนี้ขึ้นอยู่กับวิธีสร้างการฝังและประเภทการค้นหาที่ต้องการ
คุณอาจต้องทดลองใช้ COSINE หรือ EUCLIDEAN เพื่อพิจารณาว่าวิธีใดเหมาะกับกรณีการใช้งานของคุณมากที่สุด
ไม่แน่ใจว่าข้อมูลได้รับการปรับให้เป็นมาตรฐานหรือไม่
หากไม่แน่ใจว่าข้อมูลได้รับการปรับให้เป็นมาตรฐานหรือไม่ และต้องการใช้ DOT_PRODUCT เราขอแนะนำให้ใช้ COSINE แทน
COSINE เปรียบเสมือน DOT_PRODUCT ที่มีการปรับมาตรฐานข้อมูลในตัว
ระยะทางที่วัดโดยใช้ COSINE มีตั้งแต่ 0 ถึง 2 ผลลัพธ์ที่ใกล้เคียงกับ 0 บ่งชี้ว่าเวกเตอร์มีความคล้ายกันมาก
เอกสารแผ่นกรองขั้นต้น
หากต้องการกรองเอกสารล่วงหน้าก่อนค้นหาเพื่อนบ้านที่ใกล้ที่สุด คุณสามารถรวมการค้นหาความคล้ายคลึงกับโอเปอเรเตอร์การค้นหาอื่นๆ ได้ ระบบรองรับตัวกรองแบบผสม and และ or ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวกรองช่องที่รองรับได้ที่โอเปอเรเตอร์การค้นหา
Python
Node.js
// Similarity search with pre-filter // Requires composite vector index const preFilteredVectorQuery: VectorQuery = coll .where("color", "==", "red") .findNearest({ vectorField: "embedding_field", queryVector: [3.0, 1.0, 2.0], limit: 5, distanceMeasure: "EUCLIDEAN", }); const vectorQueryResults = await preFilteredVectorQuery.get();
Go
Java
import com.google.cloud.firestore.VectorQuery; import com.google.cloud.firestore.VectorQuerySnapshot; VectorQuery preFilteredVectorQuery = coll .whereEqualTo("color", "red") .findNearest( "embedding_field", new double[] {3.0, 1.0, 2.0}, /* limit */ 10, VectorQuery.DistanceMeasure.EUCLIDEAN); ApiFuture<VectorQuerySnapshot> future = preFilteredVectorQuery.get(); VectorQuerySnapshot vectorQuerySnapshot = future.get();
ดึงข้อมูลระยะทางเวกเตอร์ที่คำนวณได้
คุณสามารถดึงข้อมูลระยะทางเวกเตอร์ที่คำนวณได้โดยกำหนดชื่อพร็อพเพอร์ตี้เอาต์พุต distance_result_field ในการค้นหา FindNearest ดังที่แสดงในตัวอย่างต่อไปนี้
Python
Node.js
const vectorQuery: VectorQuery = coll.findNearest( { vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN', distanceResultField: 'vector_distance' }); const snapshot: VectorQuerySnapshot = await vectorQuery.get(); snapshot.forEach((doc) => { console.log(doc.id, ' Distance: ', doc.get('vector_distance')); });
Go
Java
import com.google.cloud.firestore.VectorQuery; import com.google.cloud.firestore.VectorQueryOptions; import com.google.cloud.firestore.VectorQuerySnapshot; VectorQuery vectorQuery = coll.findNearest( "embedding_field", new double[] {3.0, 1.0, 2.0}, /* limit */ 10, VectorQuery.DistanceMeasure.EUCLIDEAN, VectorQueryOptions.newBuilder().setDistanceResultField("vector_distance").build()); ApiFuture<VectorQuerySnapshot> future = vectorQuery.get(); VectorQuerySnapshot vectorQuerySnapshot = future.get(); for (DocumentSnapshot document : vectorQuerySnapshot.getDocuments()) { System.out.println(document.getId() + " Distance: " + document.get("vector_distance")); }
หากต้องการใช้มาสก์ฟิลด์เพื่อแสดงชุดย่อยของฟิลด์เอกสารพร้อมกับ distanceResultField คุณต้องใส่ค่าของ distanceResultField ในมาสก์ฟิลด์ด้วย ดังที่แสดงในตัวอย่างต่อไปนี้
Python
Node.js
const vectorQuery: VectorQuery = coll .select('name', 'description', 'vector_distance') .findNearest({ vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN', distanceResultField: 'vector_distance' });
Go
Java
import com.google.cloud.firestore.VectorQuery; import com.google.cloud.firestore.VectorQueryOptions; import com.google.cloud.firestore.VectorQuerySnapshot; VectorQuery vectorQuery = coll .select("name", "description", "vector_distance") .findNearest( "embedding_field", new double[] {3.0, 1.0, 2.0}, /* limit */ 10, VectorQuery.DistanceMeasure.EUCLIDEAN, VectorQueryOptions.newBuilder() .setDistanceResultField("vector_distance") .build()); ApiFuture<VectorQuerySnapshot> future = vectorQuery.get(); VectorQuerySnapshot vectorQuerySnapshot = future.get(); for (DocumentSnapshot document : vectorQuerySnapshot.getDocuments()) { System.out.println(document.getId() + " Distance: " + document.get("vector_distance")); }
ระบุเกณฑ์ระยะทาง
คุณสามารถระบุเกณฑ์ความคล้ายคลึงที่จะแสดงผลเฉพาะเอกสารที่อยู่ภายในเกณฑ์เท่านั้น ลักษณะการทำงานของช่องเกณฑ์จะขึ้นอยู่กับการวัดระยะทางที่คุณเลือก ดังนี้
- ระยะทาง
EUCLIDEANและCOSINEจะจำกัดเกณฑ์ไว้ที่เอกสารซึ่งมีระยะทางน้อยกว่าหรือเท่ากับเกณฑ์ที่ระบุ การวัดระยะทางเหล่านี้จะลดลงเมื่อเวกเตอร์มีความคล้ายกันมากขึ้น - ระยะทาง
DOT_PRODUCTจะจำกัดเกณฑ์ไว้ที่เอกสารซึ่งมีระยะทางมากกว่าหรือเท่ากับเกณฑ์ที่ระบุ ระยะทางของผลคูณสเกลาร์จะเพิ่มขึ้นเมื่อเวกเตอร์มีความคล้ายกันมากขึ้น
ตัวอย่างต่อไปนี้แสดงวิธีระบุเกณฑ์ระยะทางเพื่อแสดงเอกสารที่ใกล้ที่สุดไม่เกิน 10 รายการซึ่งอยู่ห่างออกไปไม่เกิน 4.5 หน่วยโดยใช้เมตริกระยะทาง EUCLIDEAN
Python
Node.js
const vectorQuery: VectorQuery = coll.findNearest({ vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN', distanceThreshold: 4.5 }); const snapshot: VectorQuerySnapshot = await vectorQuery.get(); snapshot.forEach((doc) => { console.log(doc.id); });
Go
Java
import com.google.cloud.firestore.VectorQuery; import com.google.cloud.firestore.VectorQueryOptions; import com.google.cloud.firestore.VectorQuerySnapshot; VectorQuery vectorQuery = coll.findNearest( "embedding_field", new double[] {3.0, 1.0, 2.0}, /* limit */ 10, VectorQuery.DistanceMeasure.EUCLIDEAN, VectorQueryOptions.newBuilder() .setDistanceThreshold(4.5) .build()); ApiFuture<VectorQuerySnapshot> future = vectorQuery.get(); VectorQuerySnapshot vectorQuerySnapshot = future.get(); for (DocumentSnapshot document : vectorQuerySnapshot.getDocuments()) { System.out.println(document.getId()); }
ข้อจำกัด
โปรดคำนึงถึงข้อจำกัดต่อไปนี้เมื่อทำงานกับการฝังเวกเตอร์
- มิติข้อมูลการฝังสูงสุดที่รองรับคือ 2048 หากต้องการจัดเก็บดัชนีขนาดใหญ่ขึ้น ให้ใช้การลดมิติข้อมูล
- จำนวนเอกสารสูงสุดที่จะแสดงผลจากการค้นหาเพื่อนบ้านใกล้ที่สุดคือ 1,000 รายการ (ข้อจำกัดของรุ่น Standard เท่านั้น)
- การค้นหาเวกเตอร์ไม่รองรับผู้ฟังภาพรวมแบบเรียลไทม์
- มีเพียงไลบรารีของไคลเอ็นต์ Python, Node.js, Go และ Java เท่านั้นที่รองรับการค้นหาเวกเตอร์
ขั้นตอนถัดไป
- อ่านเกี่ยวกับแนวทางปฏิบัติแนะนำสำหรับ Cloud Firestore
- ทำความเข้าใจการอ่านและการเขียนในวงกว้าง