دليل تطوير 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 اسم المجموعة في رابط الويب، لذا لديها بعض القيود في التسمية:

  • يجب أن يكون طول الاسم بين 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 الطريقة لإضافة البيانات إلى كروما.

أضف البيانات مباشرة دون تحديد متجهات المستندات:

collection.add(
    documents=["لوريم إيبسوم...", "doc2", "doc3", ...],
    metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
    ids=["id1", "id2", "id3", ...]
)

إذا تلقى كروما قائمة من المستندات، سوف تستخدم تلقائياً دالة التضمين للمجموعة لحساب المتجهات للمستندات (إذا لم يتم توفير دالة تضمين عند إنشاء المجموعة، سيتم استخدام القيمة الافتراضية). ستخزن كروما أيضا المستندات نفسها. إذا كان المستند كبيراً جداً بحيث لا يمكن حسابه باستخدام دالة التضمين المحددة، سيحدث استثناء.

يجب أن يحتوي كل مستند على معرف فريد (ids). ستؤدي إضافة نفس المعرف مرتين إلى تخزين القيمة الأولية فقط. بشكل اختياري، يمكنك توفير قائمة من القواميس للبيانات الوصفية (metadatas) لكل مستند، لتخزين معلومات إضافية يمكن استخدامها لتصفية البيانات أثناء الاستعلامات.

بديلاً، يمكنك توفير مباشرة قائمة ببيانات المتجه المتعلقة بالمستند، وستستخدم كروما البيانات المتجهية التي قدمتها بدون حساب تلقائي للمتجهات.

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", ...]
)

إذا لم تتطابق أبعاد البيانات المتجهية المقدمة (الطول) مع أبعاد المجموعة، سيحدث استثناء.

يمكنك أيضا تخزين المستندات في مكان آخر وتقديم كروما بالبيانات المتجهية وقائمة البيانات الوصفية. يمكنك استخدام المعرفات لربط المتجهات بالمستندات المخزنة في مكان آخر.

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، طالما كانت مرتبطة عبر المعرفات.

الاستعلام عن بيانات المجموعة

يمكن استخدام الوظيفة .query للاستعلام عن مجموعات بيانات كروما بعدة طرق.

يمكنك الاستعلام باستخدام مجموعة من query_embeddings (بيانات الناقل).

نصيحة: في سيناريوهات التطوير الحقيقية، يتم الحصول على query_embeddings عادةً أولاً عن طريق حساب الناقل لاستعلام المستخدم من خلال نموذج تضمين النص، ومن ثم استخدام هذا الناقل للاستعلام عن المحتوى المماثل.

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"}
)

سيقوم الاستعلام بإرجاع n_results النتائج التي تتطابق أفضل مع كل ناقل استعلام (query_embedding) بالتسلسل. يمكن توفير قاموس تصفية where اختياري لتصفية النتائج استناداً إلى البيانات الوصفية المرتبطة بكل مستند. بالإضافة إلى ذلك، يمكن توفير قاموس تصفية where_document اختياري لتصفية النتائج استناداً إلى محتوى المستند.

إذا لم تكن query_embeddings المقدمة متوافقة مع أبعاد المجموعة، فسيحدث استثناء. لضمان أبعاد الناقل متسقة، استخدم نفس نموذج تضمين النص لحساب النوافذ.

يمكنك أيضًا الاستعلام باستخدام مجموعة من نصوص الاستعلام. ستقوم كروما أولاً بحساب الناقل لكل نص استعلام باستخدام وظيفة التضمين للمجموعة، ومن ثم تنفذ الاستعلام باستخدام نوافذ النص المُنشأ.

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

يمكنك أيضًا استخدام .get للاستعلام عن البيانات من المجموعة بواسطة الهوية.

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

.get يدعم أيضًا تصفية where و where_document. إذا لم يتم توفير الهوية، فسيقوم بإرجاع جميع العناصر في المجموعة التي تتطابق مع تصفية where و where_document.

تحديد حقول الإرجاع

عند استخدام get أو query، يمكنك استخدام المعلمة include لتحديد البيانات المراد إرجاعها -- embeddings, documents, أو metadatas، ويجب عند الاستعلام عن البيانات إرجاع بيانات المسافات. بشكل افتراضي، تقوم كروما بإرجاع المستندات والبيانات الوصفية، وتقوم بإرجاع بيانات المسافات للاستعلامات، بينما "ids" يقوم دائمًا بالإرجاع. يمكنك تحديد الحقول المراد إرجاعها عن طريق تمرير مصفوفة لأسماء الحقول إلى معلمة includes في طريقة الاستعلام أو get.

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

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

استخدام تصفية البحث

يدعم كروما تصفية الاستعلامات استنادًا إلى البيانات الوصفية ومحتوى الوثيقة. يتم استخدام تصفية where لتصفية البيانات الوصفية، ويتم استخدام تصفية where_document لتصفية محتوى الوثيقة، ويشرح ما يلي كيفية كتابة تعابير شروط التصفية.

التصفية بواسطة البيانات الوصفية

لتصفية البيانات الوصفية، يجب توفير قاموس تصفية where للاستعلام. يجب أن يكون للقاموس الهيكل التالي:

{
    "metadata_field": {
        <المشغل>: <القيمة>
    }
}

يدعم تصفية البيانات الوصفية المشغلات التالية:

  • $eq - يساوي (سلسلة نصية، عدد صحيح، عدد عشري)
  • $ne - لا يساوي (سلسلة نصية، عدد صحيح، عدد عشري)
  • $gt - أكبر من (عدد صحيح، عدد عشري)
  • $gte - أكبر من أو يساوي (عدد صحيح، عدد عشري)
  • $lt - أقل من (عدد صحيح، عدد عشري)
  • $lte - أقل من أو يساوي (عدد صحيح، عدد عشري)

استخدام المشغل $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", ...],
)

إذا لم يتم العثور على معرف في المجموعة، سيتم تسجيل خطأ وسيتم تجاهل التحديث. إذا لم يكن للمستند المقدم نفس الفيكتور المقابل، سيتم استخدام وظيفة الفيكتور للمجموعة لحساب الفيكتور.

إذا كانت بيانات الفيكتور المقدمة ذات بُعد مختلف عن الكولكشن، ستحدث استثناء.

تدعم كروما أيضًا عملية الـ 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", ...],
)

حذف بيانات المجموعة

تدعم كروما استخدام .delete لإزالة البيانات من مجموعة بواسطة id. سيتم حذف الفيكتورات، المستندات، والبيانات المرتبطة مع كل بيانات أيضًا.

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

.delete تدعم أيضًا فلتر where. إذا لم يتم تقديم معرف، سيقوم بحذف جميع العناصر في المجموعة التي تطابق فلتر where.