คู่มือการพัฒนาละเอียดเกี่ยวกับ Python Chromadb

การติดตั้ง

pip install chromadb

การจัดเก็บข้อมูลของ Chromadb

import chromadb

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

client = chromadb.PersistentClient(path="/data/tizi365.db")

พารามิเตอร์ path คือเส้นทางไปยังไฟล์ฐานข้อมูลของ Chroma

หมายเหตุ: สำหรับฐานข้อมูลของ Chroma การสร้างวัตถุไคลเอ็นต์ครั้งเดียวพอ การโหลดและบันทึกลูกค้าหลายๆ คนในเส้นทางเดียวกันอาจนำไปสู่พฤติกรรมที่ไม่คาดคิด เช่นการลบข้อมูล โดยทั่วไปแล้วแค่สร้างไคลเอ็นต์ Chroma คนเดียวในแอพพลิเคชั่นก็พอเพียง

ฟังก์ชันที่ใช้บ่อยของวัตถุไคลเอ็นต์:

client.reset()  # ล้างและรีเซ็ตฐานข้อมูลอย่างสมบูรณ์

การดำเนินการของคอลเล็กชัน

Chromadb ใช้คอลเล็กชัน collection เพื่อการบริหารจัดการกับข้อมูลเวกเตอร์ซึ่งสามารถเปรียบเสมือนกับตารางใน MYSQL

การสร้าง การดู และลบคอลเล็กชัน

Chroma ใช้ชื่อคอลเล็กชันใน URL ดังนั้นมีหลายข้อจำกัดในการตั้งชื่อ:

  • ความยาวของชื่อต้องอยู่ระหว่าง 3 ถึง 63 ตัวอักษร
  • ชื่อต้องขึ้นต้นและลงท้ายด้วยตัวอักษรพิมพ์เล็กหรือตัวเลข และสามารถมีจุด, ขีดล่าง, และขีดบรรจุในระหว่าง
  • ชื่อไม่สามารถมีจุดสองติดกัน
  • ชื่อไม่สามารถเป็นที่อยู่ IP ที่ถูกต้อง

เพื่อสร้างคอลเล็กชัน คุณจำเป็นต้องระบุชื่อคอลเล็กชันและฟังก์ชันการคำนวณเวกเตอร์ทางเลือก (เรียกว่าฟังก์ชันฝังตัว) หากมีฟังก์ชันฝังตัวจะต้องระบุทุกครั้งที่มีการเข้าถึงคอลเล็กชัน

หมายเหตุ: วัตถุของฟังก์ชันการคำนวณเวกเตอร์ (ฟังก์ชันฝังตัว) มีวัตถุคือคำนวณเวกเตอร์ข้อความ

collection = client.create_collection(name="my_collection", embedding_function=emb_fn)
collection = client.get_collection(name="my_collection", embedding_function=emb_fn)

ฟังก์ชันฝังตัวรับข้อความเป็นอินพุตและคืนเวกเตอร์ที่คำนวณได้

หมายเหตุ: ผู้เริ่มต้นสามารถเรียนรู้เกี่ยวกับคู่มือการเรียนรู้โมเดลการฝังข้อความ

คุณสามารถอ้างอิงถึงคอลเล็กชันที่มีอยู่ด้วยฟังก์ชัน .get_collection และใช้ .delete_collection เพื่อลบคอลเล็กชัน คุณยังสามารถใช้ .get_or_create_collection เพื่ออ้างถึงคอลเล็กชัน (หากมีอยู่) หรือสร้างมันหากไม่มี

collection = client.get_collection(name="tizi365")
collection = client.get_or_create_collection(name="tizi365")
client.delete_collection(name="tizi365")

ดำเนินการของคอลเล็กชันที่ใช้บ่อยอื่นๆ:

collection.peek() # คืนค่าลิสต์ของข้อมูล 10 ตัวแรกในคอลเล็กชัน
collection.count() # คืนค่าจำนวนรวมของข้อมูลในคอลเล็กชัน
collection.modify(name="new_name") # เปลี่ยนชื่อคอลเล็กชัน

การกำหนดวิธีการคำนวณระยะห่างของเวกเตอร์

ฟังก์ชัน create_collection ยังรวมพารามิเตอร์ข้อมูลเสริมที่เป็นทางเลือกด้วย โดยการตั้งค่าของ hnsw:space เพื่อปรับแต่งวิธีการคำนวณระยะห่างของเวกเตอร์

หมายเหตุ: ข้อมูลเวกเตอร์แทนความคล้ายคลึงระหว่างเวกเตอร์โดยการคำนวณระยะห่างของพื้นที่ระหว่างเวกเตอร์ ระยะห่างที่ใกล้ที่สุด ความคล้ายคลึงสูงขึ้นและถกลับกัน

collection = client.create_collection(
        name="collection_name",
        metadata={"hnsw:space": "cosine"} # l2 เป็นวิธีการคำนวณเริ่มต้น
    )

ตัวเลือกที่ถูกต้องสำหรับ hnsw:space คือ "l2", "ip", หรือ "cosine" เริ่มต้นคือ "l2"

เพิ่มข้อมูลลงในคอลเล็กชัน

ใช้ .add เมท็อดเพื่อเพิ่มข้อมูลลงใน Chroma

เพิ่มข้อมูลโดยตรงโดยไม่ระบุเวกเตอร์ของเอกสาร:

collection.add(
    documents=["lorem ipsum...", "doc2", "doc3", ...],
    metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

หาก Chroma ได้รับรายการของเอกสาร จะใช้ฟังก์ชันเวกเตอร์ของคอลเล็กชันเพื่อคำนวณเวกเตอร์สำหรับเอกสารโดยอัตโนมัติ (หากไม่มีการระบุฟังก์ชันเวกเตอร์เมื่อสร้างคอลเล็กชัน ค่าเริ่มต้นจะถูกใช้) Chroma ยังจะเก็บเอกสารเองด้วย หากเอกสารมีขนาดใหญ่เกินไปที่จะคำนวณโดยใช้ฟังก์ชันเวกเตอร์ที่ถูกเลือก ข้อยกเว้นจะเกิดขึ้น

แต่ละเอกสารต้องมี ID ที่ไม่ซ้ำกัน (ids) การเพิ่ม ID เดียวกันสองครั้งจะทำให้การจัดเก็บค่าเริ่มต้นอย่างเดียว เพิ่มเติมได้ที่คุณสามารถให้รายการของพจนานุกรมเมตาดาต้า (metadatas) สำหรับแต่ละเอกสารเพื่อเก็บข้อมูลเพิ่มเติมที่สามารถใช้สำหรับการกรองข้อมูลระหว่างการค้นหา

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

collection.add(
    documents=["doc1", "doc2", "doc3", ...],
    embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

หากมิติข้อมูลเวกเตอร์ที่ให้ไม่ตรงกับมิติของคอลเล็กชัน จะเกิดข้อยกเว้นขึ้น

คุณยังสามารถเก็บเอกสารที่อื่นไว้และให้ Chroma ด้วยข้อมูลเวกเตอร์และรายการเมตาดาต้า คุณสามารถใช้ id เพื่อเชื่อมโยงเวกเตอร์กับเอกสารที่เก็บไว้ที่อื่น

collection.add(
    embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

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

การสอบถามข้อมูลชุดข้อมูล

เมธอด .query สามารถใช้ในการสอบถามชุดข้อมูล Chroma ในหลายรูปแบบ

คุณสามารถสอบถามโดยใช้ชุด query_embeddings (ข้อมูลเวกเตอร์)

เคล็ดลับ: ในสถานการณ์การพัฒนาจริง ๆ query_embeddings มักจะได้รับโดยการคำนวณเวกเตอร์ของคำค้นของผู้ใช้ผ่านโมเดล text embedding ก่อน แล้วจึงใช้เวกเตอร์นี้ในการสอบถามเนื้อหาที่คล้ายกัน

collection.query(
    query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
    n_results=10,
    where={"metadata_field": "is_equal_to_this"},
    where_document={"$contains":"search_string"}
)

การสอบถามจะคืนผลลัพธ์ที่ดีที่สุดสำหรับทุกเวกเตอร์คำค้น (query_embedding) ที่กำหนด ตามลำดับ สามารถให้แบบกรอง where เพื่อกรองผลลัพธ์ตาม metadata ที่เกี่ยวข้องกับทุกเอกสาร และสามารถให้แบบกรอง where_document เพื่อกรองผลลัพธ์ตามเนื้อหาของเอกสาร

หาก query_embeddings ที่ให้ไว้ไม่สอดคล้องกับมิติของชุดข้อมูล การเกิดข้อยกเว้นจะเกิดขึ้น ในการให้มิติเวกเตอร์ที่สอดคล้องกัน ให้ใช้โมเดล text embedding เดียวกันในการคำนวณเวกเตอร์

คุณยังสามารถสอบถามโดยใช้ชุด query texts ได้ Chroma จะคำนวณเวกเตอร์สำหรับแต่ละข้อความคำค้นโดยใช้ฟังก์ชันการฝังเข็มของคอลเลคชัน และจากนั้นทำการสอบถามโดยใช้เวกเตอร์ข้อความที่สร้างขึ้น

collection.query(
    query_texts=["doc10", "thus spake zarathustra", ...],
    n_results=10,
    where={"metadata_field": "is_equal_to_this"},
    where_document={"$contains":"search_string"}
)

คุณยังสามารถใช้ .get เพื่อสอบถามข้อมูลจากคอลเลคชันตาม id

collection.get(
    ids=["id1", "id2", "id3", ...],
    where={"style": "style1"}
)

.get ยังรองรับการกรอง where และ where_document หากไม่มี id ที่กำหนด จะคืนค่ารายการทั้งหมดในคอลเลคชันที่สอดคล้องกับ where และ where_document

การระบุฟิลด์ที่ต้องการคืน

ในการใช้ get หรือ query คุณสามารถใช้พารามิเตอร์ include เพื่อระบุข้อมูลที่ต้องการที่จะคืน-- embeddings, documents, หรือ metadatas, และสำหรับ query ต้องมีการคืนข้อมูลระยะห่าง ตามค่าเริ่มต้น Chroma จะคืนเอกสารและเมตาดาต้า และคืนข้อมูลระยะห่างสำหรับการสอบถาม ในขณะที่ "ids" จะคุณสามารถระบุฟิลด์ที่ต้องการคืนโดยการส่งอาร์เรย์ของชื่อฟิลด์ไปยังพารามิเตอร์ includes ของเมท็อด query หรือ get

collection.get(
    include=["documents"]
)

collection.query(
    query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
    include=["documents"]
)

การใช้ Where Filters

Chroma รองรับการกรองคำค้นโดยใช้ metadata และเนื้อหาของเอกสาร ฟิลเตอร์ where ใช้สำหรับกรองเมตาดาต้า และ where_document ใช้สำหรับกรองเนื้อหาเอกสาร และต่อไปนี้จะอธิบายวิธีการเขียนสูตรกรองเงื่อนไข

กรองโดย Metadata

เพื่อกรองเมตาดาต้า คุณต้องให้รายการฟิลเตอร์ where เพื่อการค้นคว้า รายการต้องมีโครงสร้างดังนี้

{
    "metadata_field": {
        <Operator>: <Value>
    }
}

การกรองเมตาดาต้ารองรับตัวดำเนินการต่อไปนี้:

  • $eq - เท่ากับ (string, integer, float)
  • $ne - ไม่เท่ากับ (string, integer, float)
  • $gt - มากกว่า (int, float)
  • $gte - มากกว่าหรือเท่ากับ (int, float)
  • $lt - น้อยกว่า (integer, float)
  • $lte - น้อยกว่าหรือเท่ากับ (int, float)

การใช้ตัวดำเนินการ $eq คือเทียบเท่ากับการใช้กรอง where

{
    "metadata_field": "search_string"
}

{
    "metadata_field": {
        "$eq": "search_string"
    }
}

กรองเนื้อหาของเอกสาร

เพื่อกรองเนื้อหาของเอกสาร คุณต้องให้รายการฟิลเตอร์ where_document เพื่อการค้นคว้า รายการต้องมีโครงสร้างดังนี้:

{
    "$contains": "search_string"
}

การใช้ตัวดำเนินการทางตรรกะ

คุณยังสามารถใช้ตัวดำเนินการทางตรรกะ $and และ $or เพื่อรวมฟิลเตอร์หลายรายการเข้าด้วยกัน

ตัวดำเนินการ $and จะส่งคืนผลลัพธ์ที่ตรงกับเงื่อนไขทั้งหมดในรายการ

{
    "$and": [
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        },
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        }
    ]
}

ตัวดำเนินการ $or จะส่งคืนผลลัพธ์ที่ตรงกับเงื่อนไขใดก็ตามในรายการ

{
    "$or": [
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        },
        {
            "metadata_field": {
                <Operator>: <Value>
            }
        }
    ]
}

การปรับปรุงข้อมูลในคอลเลกชัน

การใช้ .update ช่วยให้คุณสามารถปรับปรุงคุณสมบัติใดๆ ของข้อมูลในคอลเลกชันได้

collection.update(
    ids=["id1", "id2", "id3", ...],
    embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
    documents=["doc1", "doc2", "doc3", ...],
)

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

หากข้อมูลเวกเตอร์ที่ให้มามีมิติที่แตกต่างกับคอลเลกชัน จะเกิดข้อยกเว้นขึ้น

Chroma ยังรองรับการดำเนินการ upsert ซึ่งสามารถปรับปรุงข้อมูลที่มีอยู่และแทรกข้อมูลใหม่หากยังไม่มีอยู่

collection.upsert(
    ids=["id1", "id2", "id3", ...],
    embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
    metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
    documents=["doc1", "doc2", "doc3", ...],
)

การลบข้อมูลในคอลเลกชัน

Chroma รองรับการใช้ .delete เพื่อลบข้อมูลออกจากคอลเลกชันตาม id โดยเฉพาะ และเวกเตอร์ เอกสาร และเมตาดาต้าที่เกี่ยวข้องกับแต่ละข้อมูลจะถูกลบออกด้วย

collection.delete(
    ids=["id1", "id2", "id3",...],
    where={"chapter": "20"}
)

.delete ยังรองรับตัวกรอง where หากไม่มี id ที่ให้มา จะลบรายการทั้งหมดในคอลเลกชันที่ตรงกับตัวกรอง where ไว้