หน้านี้แสดงวิธีใช้ Cloud Firestore เพื่อทำการค้นหาเวกเตอร์ K-เพื่อนบ้านที่ใกล้ที่สุด (KNN) โดยใช้เทคนิคต่อไปนี้
- จัดเก็บค่าเวกเตอร์
- สร้างและจัดการดัชนีเวกเตอร์ KNN
- ทำการค้นหา K-เพื่อนบ้านที่ใกล้ที่สุด (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 Functions
หากต้องการคำนวณและจัดเก็บการฝังเวกเตอร์ทุกครั้งที่เอกสารได้รับการอัปเดตหรือ สร้างขึ้น คุณสามารถตั้งค่าCloud Functionsได้ดังนี้
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 คือรหัสของฐานข้อมูล
ทำการค้นหาเพื่อนบ้านที่ใกล้ที่สุด
คุณสามารถทำการค้นหาความคล้ายคลึงเพื่อค้นหาเพื่อนบ้านที่ใกล้ที่สุดของการฝังเวกเตอร์ได้ การค้นหาความคล้ายคลึงต้องใช้ ดัชนีเวกเตอร์ หากไม่มีดัชนี 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ระหว่างเวกเตอร์ ดูข้อมูลเพิ่มเติมได้ที่ EuclideanCOSINE: เปรียบเทียบเวกเตอร์ตามมุมระหว่างเวกเตอร์ ซึ่งช่วยให้คุณวัดความคล้ายคลึงที่ไม่ขึ้นอยู่กับขนาดของเวกเตอร์ได้ เราขอแนะนำให้ใช้DOT_PRODUCTกับเวกเตอร์ที่ทำให้เป็นมาตรฐานหน่วยแทนระยะทาง COSINE ซึ่งเทียบเท่ากันทางคณิตศาสตร์และมีประสิทธิภาพดีกว่า ดูข้อมูลเพิ่มเติมได้ที่ ความคล้ายคลึงแบบโคไซน์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 รายการ (ข้อจำกัดของรุ่นมาตรฐานเท่านั้น)
- การค้นหาเวกเตอร์ไม่รองรับ Listener สแนปชอตแบบเรียลไทม์
- มีเพียงไลบรารีของไคลเอ็นต์ Python, Node.js, Go และ Java เท่านั้นที่รองรับการค้นหาเวกเตอร์
ขั้นตอนถัดไป
- อ่านข้อมูลเกี่ยวกับแนวทางปฏิบัติแนะนำสำหรับCloud Firestore
- ทำความเข้าใจการอ่านและการเขียนข้อมูลในวงกว้าง