ค้นหาด้วยการฝังเวกเตอร์

หน้านี้แสดงวิธีใช้ Cloud Firestore เพื่อทำ K ให้อยู่ใกล้ที่สุด ค้นหาเวกเตอร์เพื่อนบ้าน (KNN) โดยใช้เทคนิคต่อไปนี้

  • เก็บค่าเวกเตอร์
  • สร้างและจัดการดัชนีเวกเตอร์ KNN
  • สร้างการค้นหา K-Nabest-Neighbor (KNN) โดยใช้เวกเตอร์ที่รองรับ การวัดระยะทาง

การฝังเวกเตอร์ที่จัดเก็บ

คุณสามารถสร้างค่าเวกเตอร์ เช่น การฝังข้อความ จาก Cloud Firestore และจัดเก็บไว้ในเอกสาร Cloud Firestore ฉบับ

การดำเนินการเขียนที่มีการฝังเวกเตอร์

ตัวอย่างต่อไปนี้แสดงวิธีจัดเก็บการฝังเวกเตอร์ใน เอกสาร Cloud Firestore รายการ:

Python
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector

firestore_client = firestore.Client()
collection = firestore_client.collection("coffee-beans")
doc = {
    "name": "Kahawa coffee beans",
    "description": "Information about the Kahawa coffee beans.",
    "embedding_field": Vector([1.0, 2.0, 3.0]),
}

collection.add(doc)
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])
});

การฝังเวกเตอร์การประมวลผลด้วย 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,
  });
}

สร้างและจัดการดัชนีเวกเตอร์

ก่อนที่คุณจะสามารถค้นหาเพื่อนบ้านที่อยู่ใกล้ที่สุดด้วยการฝังเวกเตอร์ของคุณ คุณต้องสร้างดัชนีที่เกี่ยวข้อง ตัวอย่างต่อไปนี้แสดง วิธีสร้างและจัดการดัชนีเวกเตอร์

สร้างดัชนีเวกเตอร์

ก่อนสร้างดัชนีเวกเตอร์ ให้อัปเกรดเป็น Google Cloud CLI เวอร์ชันล่าสุด:

gcloud components update

หากต้องการสร้างดัชนีเวกเตอร์ ให้ใช้ gcloud firestore indexes composite create ดังนี้

gcloud
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
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

แสดงรายการดัชนีเวกเตอร์ทั้งหมด

gcloud
gcloud firestore indexes composite list --database=database-id

แทนที่ database-id ด้วยรหัสของฐานข้อมูล

ลบดัชนีเวกเตอร์

gcloud
gcloud firestore indexes composite delete index-id --database=database-id

โดยมี

  • index-id คือรหัสของดัชนีที่จะลบ ใช้ indexes composite list เพื่อดึงข้อมูลรหัสดัชนี
  • database-id คือรหัสของฐานข้อมูล

อธิบายดัชนีเวกเตอร์

gcloud
gcloud firestore indexes composite describe index-id --database=database-id

โดยมี

  • index-id คือรหัสของดัชนีที่จะอธิบาย ใช้หรือ indexes composite list เพื่อเรียกข้อมูลรหัสดัชนี
  • database-id คือรหัสของฐานข้อมูล

ค้นหาเพื่อนบ้านที่อยู่ใกล้ที่สุด

คุณสามารถใช้การค้นหาความคล้ายคลึงกันเพื่อค้นหาเพื่อนบ้านที่ใกล้ที่สุดของ การฝังเวกเตอร์ การค้นหาความคล้ายคลึงกันต้องใช้ดัชนีเวกเตอร์ หากไม่มีดัชนี Cloud Firestore จะแนะนำดัชนีที่จะสร้าง โดยใช้ gcloud CLI

ตัวอย่างต่อไปนี้จะค้นหาเพื่อนบ้านที่ใกล้เคียงที่สุด 10 คนของเวกเตอร์การค้นหา

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

# Requires a single-field vector index
vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([3.0, 1.0, 2.0]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=5,
)
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();

ระยะทางเวกเตอร์

การค้นหาเพื่อนบ้านที่ใกล้ที่สุดรองรับตัวเลือกต่อไปนี้สำหรับระยะทางเวกเตอร์

  • EUCLIDEAN: วัดระยะห่าง EUCLIDEAN ระหว่างเวกเตอร์ ดูข้อมูลเพิ่มเติมได้ที่ ยุคลิด
  • COSINE: เปรียบเทียบเวกเตอร์ตามมุมระหว่างเวกเตอร์ ซึ่งจะช่วยให้คุณ วัดความคล้ายคลึงกันที่ไม่ได้อิงตามขนาดเวกเตอร์ เราขอแนะนำให้ใช้ DOT_PRODUCT กับเวกเตอร์ที่ได้รับการปรับให้เป็นหน่วยมาตรฐานแทน COSINE ซึ่งมีความเทียบเท่าทางคณิตศาสตร์และดีกว่า ด้านประสิทธิภาพ หากต้องการดูข้อมูลเพิ่มเติม โปรดดู ความคล้ายคลึงกันของโคไซน์เพื่อเรียนรู้ และอีกมากมาย
  • DOT_PRODUCT: คล้ายกับ COSINE แต่ได้รับผลกระทบจากขนาดของ เวกเตอร์ ดูข้อมูลเพิ่มเติมได้ที่ ผลิตภัณฑ์ Dot

เลือกการวัดระยะทาง

ทั้งนี้ขึ้นอยู่กับว่าการฝังเวกเตอร์ทั้งหมดได้รับการทำให้เป็นมาตรฐานหรือไม่ คุณสามารถ กำหนดวิธีวัดระยะทางที่จะใช้ค้นหาการวัดระยะทาง A ที่ปรับให้เป็นมาตรฐาน การฝังเวกเตอร์มีขนาด (ความยาว) เท่ากับ 1.0

นอกจากนี้ หากคุณทราบว่าโมเดลของคุณใช้หน่วยวัดระยะทางใด ให้ใช้การวัดระยะทางนั้นเพื่อคำนวณระยะทางระหว่างเวกเตอร์ของคุณ การฝังวิดีโอ

ข้อมูลมาตรฐาน

ถ้าคุณมีชุดข้อมูลที่มีการฝังเวกเตอร์ทั้งหมดให้เป็นมาตรฐาน ทั้งสาม การวัดระยะทางจะแสดงผลการค้นหาเชิงความหมายเดียวกัน โดยพื้นฐานแล้ว แม้ว่าแต่ละ มาตรวัดระยะทางจะแสดงผลค่าที่แตกต่างกัน โดยค่าเหล่านั้นจะจัดเรียงในลักษณะเดียวกัน วันและเวลา การฝังจะถูกทำให้เป็นมาตรฐาน โดย DOT_PRODUCT มักจะเป็นการคำนวณที่ มีประสิทธิภาพ แต่กรณีส่วนใหญ่มีความแตกต่างกันน้อยมาก อย่างไรก็ตาม หาก แอปพลิเคชันมีความละเอียดอ่อนด้านประสิทธิภาพสูง DOT_PRODUCT อาจช่วยได้ ในการปรับแต่งประสิทธิภาพ

ข้อมูลที่ไม่ใช่ค่ามาตรฐาน

หากคุณมีชุดข้อมูลที่ไม่ได้ทำให้การฝังเวกเตอร์เป็นมาตรฐาน การใช้ DOT_PRODUCT เป็นระยะทางก็ไม่ถูกต้องในทางคณิตศาสตร์ วัดระยะทางเนื่องจากผลิตภัณฑ์แบบจุดไม่ได้วัดระยะทาง แล้วแต่กรณี เกี่ยวกับวิธีการสร้างการฝัง และประเภทการค้นหาที่ต้องการ การวัดระยะทาง COSINE หรือ EUCLIDEAN ทำให้เกิด ผลการค้นหาที่เป็นนามธรรมที่ดีกว่าการวัดระยะทางอื่นๆ การทดสอบกับ COSINE หรือ EUCLIDEAN อาจ เป็นสิ่งจำเป็นในการพิจารณาว่าวิธีใดเหมาะกับกรณีการใช้งานของคุณที่สุด

ไม่แน่ใจว่าข้อมูลได้รับการทำให้เป็นมาตรฐานหรือไม่ได้ปรับให้เป็นมาตรฐาน

หากไม่แน่ใจว่าข้อมูลได้รับการปรับให้เป็นมาตรฐานหรือไม่ และต้องการใช้ DOT_PRODUCT เราขอแนะนำให้ใช้ COSINE แทน COSINE เหมือนกับ DOT_PRODUCT ที่มีการปรับรูปแบบมาตรฐานในตัว ระยะทางวัดโดยใช้ช่วงCOSINE ตั้งแต่ 0 ถึง 2 ผลลัพธ์ ที่อยู่ใกล้กับ 0 แสดงว่าเวกเตอร์คล้ายกันมาก

กรองเอกสารล่วงหน้า

ในการกรองเอกสารล่วงหน้าก่อนที่จะพบเพื่อนบ้านที่อยู่ใกล้ที่สุด คุณสามารถรวม การค้นหาที่คล้ายกันกับโอเปอเรเตอร์ข้อความค้นหาอื่นๆ and และ สนับสนุนตัวกรองผสม or รายการ โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับตัวกรองช่องที่รองรับได้ที่โอเปอเรเตอร์การค้นหา

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

# Similarity search with pre-filter
# Requires a composite vector index
vector_query = collection.where("color", "==", "red").find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([3.0, 1.0, 2.0]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=5,
)
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();

ดึงข้อมูลระยะทางเวกเตอร์ที่คำนวณ

คุณสามารถดึงระยะทางเวกเตอร์ที่คำนวณโดยการกำหนด ชื่อพร็อพเพอร์ตี้เอาต์พุต distance_result_field ในการค้นหา FindNearest เป็น ที่แสดงในตัวอย่างต่อไปนี้

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([3.0, 1.0, 2.0]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_result_field="vector_distance",
)

docs = vector_query.stream()

for doc in docs:
    print(f"{doc.id}, Distance: {doc.get('vector_distance')}")
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'));
});

หากต้องการใช้มาสก์ช่องเพื่อแสดงผลชุดย่อยของช่องเอกสารพร้อมกับ distanceResultField คุณจะต้องใส่ค่า distanceResultField ในมาสก์ของช่องด้วย ดังที่แสดงในตัวอย่างต่อไปนี้

Python
vector_query = collection.select(["color", "vector_distance"]).find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([3.0, 1.0, 2.0]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_result_field="vector_distance",
)
Node.js
const vectorQuery: VectorQuery = coll
    .select('color', 'vector_distance')
    .findNearest({
      vectorField: 'embedding_field',
      queryVector: [3.0, 1.0, 2.0],
      limit: 10,
      distanceMeasure: 'EUCLIDEAN',
      distanceResultField: 'vector_distance'
    });

ระบุเกณฑ์ระยะทาง

คุณสามารถระบุเกณฑ์ความคล้ายคลึงกันที่จะแสดงเฉพาะเอกสารภายในองค์ประกอบ ลักษณะการทำงานของช่องเกณฑ์จะขึ้นอยู่กับการวัดระยะทาง ที่คุณเลือก

  • ระยะทาง EUCLIDEAN และ COSINE จำกัดเกณฑ์สำหรับเอกสารในตำแหน่ง ระยะทางน้อยกว่าหรือเท่ากับเกณฑ์ที่ระบุ ระยะทางเหล่านี้ การวัดจะลดลงเมื่อเวกเตอร์คล้ายกันมากขึ้น
  • ระยะทาง DOT_PRODUCT จำกัดเกณฑ์สำหรับเอกสารที่มีระยะทางเท่ากับ มากกว่าหรือเท่ากับเกณฑ์ที่ระบุ ระยะห่างของผลิตภัณฑ์แบบจุด จะเพิ่มขึ้นเมื่อเวกเตอร์คล้ายกันมากขึ้น

ตัวอย่างต่อไปนี้แสดงวิธีระบุเกณฑ์ระยะทางเพื่อแสดงผลเอกสารที่ใกล้ที่สุด 10 รายการที่ห่างออกไปไม่เกิน 4.5 หน่วยโดยใช้เมตริกระยะทาง EUCLIDEAN

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([3.0, 1.0, 2.0]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_threshold=4.5,
)

docs = vector_query.stream()

for doc in docs:
    print(f"{doc.id}")
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);
});

ข้อจำกัด

โปรดทราบข้อจำกัดต่อไปนี้ขณะที่คุณทำงานกับการฝังเวกเตอร์

  • มิติข้อมูลการฝังที่สนับสนุนสูงสุดคือ 2048 หากต้องการจัดเก็บดัชนีที่ใหญ่กว่า ให้ใช้ การลดลงของมิติข้อมูล
  • จำนวนเอกสารสูงสุดที่จะแสดงจากคำค้นหาใกล้เคียงที่สุดคือ 1,000 รายการ
  • การค้นหาเวกเตอร์ไม่รองรับ Listener ของสแนปชอตแบบเรียลไทม์
  • เฉพาะไลบรารีของไคลเอ็นต์ Python และ Node.js เท่านั้นที่รองรับการค้นหาเวกเตอร์

ขั้นตอนถัดไป