> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> توثيق لنوع البيانات QBit في ClickHouse، والذي يتيح التكميم الدقيق للبحث المتجهي التقريبي

# نوع البيانات QBit

يعيد نوع البيانات `QBit` تنظيم تخزين المتجهات لتسريع عمليات البحث التقريبي. فبدلاً من تخزين عناصر كل متجه معًا، يجمع مواقع البت نفسها عبر جميع المتجهات.
يتيح ذلك تخزين المتجهات بالدقة الكاملة مع تمكينك من اختيار مستوى التكميم الدقيق وقت البحث: اقرأ عددًا أقل من البتات لتقليل I/O وتسريع العمليات الحسابية، أو عددًا أكبر من البتات للحصول على دقة أعلى. وهكذا تستفيد من مزايا السرعة الناتجة عن تقليل نقل البيانات والحسابات بفضل التكميم، مع بقاء جميع البيانات الأصلية متاحة عند الحاجة.

للتصريح بعمود من النوع `QBit`، استخدم الصياغة التالية:

```sql theme={null}
column_name QBit(element_type, dimension[, stride])
```

* `element_type` – نوع كل عنصر من عناصر المتجه. الأنواع المسموح بها هي `Int8` و`BFloat16` و`Float32` و`Float64`
* `dimension` – بُعد كل متجه
* `stride` – اختياري. عدد الأبعاد المخزنة معًا في مجموعة واحدة من التدفقات. عند عدم تحديده، تكون قيمته الافتراضية `dimension` (مجموعة واحدة). وعند تحديده، يجب أن تكون قيمة `dimension` من مضاعفات `stride`، وعندما تكون قيمة `stride` أصغر من `dimension`، يجب أن تكون أيضًا من مضاعفات 8. تُقسَّم أبعاد `dimension` إلى `dimension / stride` مجموعات متجاورة، وتُخزَّن مستويات البت الخاصة بكل مجموعة في تدفقات منفصلة. يتيح ذلك لعملية البحث ضمن أول `D` بُعدًا (حيث تكون `D` من مضاعفات `stride`) قراءة تدفقات المجموعات التي تغطي تلك الأبعاد فقط، وهو ما يفيد مع تضمينات Matryoshka.

<div id="creating-qbit">
  ## إنشاء QBit
</div>

باستخدام النوع `QBit` في تعريف عمود الجدول:

```sql theme={null}
CREATE TABLE test (id UInt32, vec QBit(Float32, 8)) ENGINE = Memory;
INSERT INTO test VALUES (1, [1, 2, 3, 4, 5, 6, 7, 8]), (2, [9, 10, 11, 12, 13, 14, 15, 16]);
SELECT vec FROM test ORDER BY id;
```

```text theme={null}
┌─vec──────────────────────┐
│ [1,2,3,4,5,6,7,8]        │
│ [9,10,11,12,13,14,15,16] │
└──────────────────────────┘
```

<div id="converting-arrays-to-qbit">
  ## تحويل المصفوفات إلى `QBit`
</div>

تُحوَّل المصفوفات إلى `QBit` عندما يتطابق طول المصفوفة مع بُعد `QBit`. ولا يلزم أن يتطابق نوع عنصر المصفوفة مع نوع عنصر `QBit`. ويُحوَّل إليه تلقائيًا أي نوع عناصر رقمي. يتيح لك ذلك نقل عمود تضمينات موجود مباشرةً إلى عمود `QBit`:

```sql theme={null}
CREATE TABLE embeddings (id UInt32, embedding Array(Float32)) ENGINE = Memory;
INSERT INTO embeddings VALUES (1, [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]), (2, [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]);

CREATE TABLE vectors (id UInt32, vec QBit(Float32, 8)) ENGINE = Memory;
INSERT INTO vectors SELECT id, embedding FROM embeddings;

SELECT * FROM vectors ORDER BY id;
```

```text theme={null}
┌─id─┬─vec───────────────────────────────┐
│  1 │ [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8] │
│  2 │ [0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1] │
└────┴───────────────────────────────────┘
```

يمكن أيضًا إجراء التحويل بشكل صريح باستخدام `CAST`، على سبيل المثال `CAST(embedding AS QBit(Float32, 8))`.

<div id="converting-qbit-to-arrays">
  ## تحويل QBit إلى مصفوفات
</div>

تعيد عملية التحويل العكسي بناء المتجه الأصلي انطلاقًا من التمثيل المنقول على مستوى البت، لذا فإن تحويل `QBit` إلى `Array` يعيد القيم المخزنة. وهذا هو عكس [تحويل المصفوفات إلى `QBit`](#converting-arrays-to-qbit):

```sql theme={null}
SELECT [1, 2, 3, 4]::QBit(Float32, 4)::Array(Float32) AS vec;
```

```text theme={null}
┌─vec───────┐
│ [1,2,3,4] │
└───────────┘
```

تستخدم المصفوفة المُعاد إنشاؤها نوع العنصر الخاص بـ `QBit`، ثم تُحوَّل عناصرها بعد ذلك إلى نوع عنصر المصفوفة المطلوب. لذلك، يعمل أيضًا `cast` يغيّر نوع العنصر أيضًا، مثل التحويل من `QBit(Float32, N)` إلى `Array(Float64)`.

تكون دورة التحويل `Array` -> `QBit` -> `Array` بلا فقدان بالنسبة إلى `Int8` و`Float32` و`Float64`. أما `BFloat16`، فهو يطابق تحويلًا مباشرًا إلى `BFloat16` — والفقد الوحيد في الدقة هو دقة `BFloat16` نفسها.

عندما لا تكون قيمة `dimension` مضاعفًا للعدد 8، تُحذف عناصر الحشو اللاحقة الموجودة في التمثيل الداخلي، لذلك تكون النتيجة دائمًا مكوّنة من `dimension` عنصرًا بالضبط.

<div id="converting-between-qbit-types">
  ## التحويل بين أنواع QBit
</div>

يمكن تحويل `QBit` إلى `QBit` آخر ما دامت قيمة `dimension` (عدد عناصر المتجه) ثابتة. ويمكن أن يتغير كلٌّ من `element_type` و`stride`؛ أما التحويل إلى `QBit` ذي `dimension` مختلف فيؤدي إلى حدوث استثناء، لأن ذلك سيغيّر المتجه نفسه.

يؤدي تغيير `element_type` إلى إعادة تكوين المتجه وتحويل كل عنصر إلى النوع الجديد، تمامًا كما في تحويل `Array` المقابل: يكون التوسيع (على سبيل المثال من `QBit(Float32, N)` إلى `QBit(Float64, N)`) دقيقًا، بينما يؤدي التضييق إلى فقدان بعض الدقة بالطريقة نفسها التي يحدث بها ذلك عند تحويل `Array` إلى نوع أضيق.

```sql theme={null}
SELECT [1, 2, 3, 4]::QBit(Float32, 4)::QBit(Float64, 4) AS vec;
```

```text theme={null}
┌─vec───────┐
│ [1,2,3,4] │
└───────────┘
```

إن تغيير [`stride`](#strides) فقط (مع الإبقاء على `element_type` نفسه) يعيد تجميع طبقات البتات المخزّنة من دون المساس بالقيم، لذا تكون العملية دائمًا من دون فقدان:

```sql theme={null}
SELECT range(16)::Array(Float32)::QBit(Float32, 16)::QBit(Float32, 16, 8)::Array(Float32)
     = range(16)::Array(Float32) AS is_lossless;
```

```text theme={null}
┌─is_lossless─┐
│           1 │
└─────────────┘
```

<div id="qbit-subcolumns">
  ## الأعمدة الفرعية لـ QBit
</div>

يوفّر `QBit` نمط وصول عبر الأعمدة الفرعية يتيح لك الوصول إلى مستويات بت الفردية في المتجهات المخزّنة. ويمكن الوصول إلى كل موضع بِت باستخدام الصيغة `.N`، حيث إن `N` هو موضع البِت:

```sql theme={null}
CREATE TABLE test (id UInt32, vec QBit(Float32, 8)) ENGINE = Memory;
INSERT INTO test VALUES (1, [0, 0, 0, 0, 0, 0, 0, 0]);
INSERT INTO test VALUES (1, [-0, -0, -0, -0, -0, -0, -0, -0]);
SELECT bin(vec.1) FROM test;
```

```text theme={null}
┌─bin(tupleElement(vec, 1))─┐
│ 00000000                  │
│ 11111111                  │
└───────────────────────────┘
```

يعتمد عدد الأعمدة الفرعية المتاحة على نوع العنصر (وعند استخدام stride، أيضًا على عدد مجموعات stride):

* `Int8`: 8 أعمدة فرعية لكل مجموعة stride (1-8)
* `BFloat16`: 16 عمودًا فرعيًا لكل مجموعة stride (1-16)
* `Float32`: 32 عمودًا فرعيًا لكل مجموعة stride (1-32)
* `Float64`: 64 عمودًا فرعيًا لكل مجموعة stride (1-64)

تتبع الأعمدة الفرعية ترتيب بحسب المجموعات: وبوجه عام، يقرأ `vec.N` مستوى البِت `(N-1) % element_size` من مجموعة stride ذات الرقم `(N-1) / element_size`. على سبيل المثال، مع `QBit(BFloat16, 4096, 1024)`، تُقسَّم الأبعاد الـ4096 إلى 4 مجموعات، تضم كل منها 1024 بُعدًا، لذا يوجد 64 عمودًا فرعيًا: تمثل `vec.1` … `vec.16` مستويات البِت لمجموعة stride الأولى (الأبعاد 1–1024)، بينما تنتمي `vec.17` … `vec.32` إلى المجموعة الثانية (الأبعاد 1025–2048)، وهكذا.

<div id="strides">
  ## stride
</div>

افتراضيًا، يخزّن `QBit` كل مستوى بت في `single stream` واحد يمتد عبر جميع أبعاد `dimension`، لذا فإن عملية البحث تقرأ دائمًا مستويات البت كاملةً عبر المتجه بأكمله. يقسّم المعلَّم الاختياري `stride` أبعاد `dimension` إلى `dimension / stride` مجموعات متجاورة، ويخزّن مستويات البت لكل مجموعة في تدفقات منفصلة. يتيح ذلك لعملية بحث تقتصر على أول `D` بُعد فقط (بحيث تكون `D` من مضاعفات `stride`) أن تقرأ فقط تدفقات المجموعات التي تغطي تلك الأبعاد — وهذا مفيد مع [تضمينات Matryoshka](https://arxiv.org/abs/2205.13147)، حيث تشكّل الأبعاد الأولى تضمينًا منخفض الأبعاد صالحًا للاستخدام.

```sql theme={null}
CREATE TABLE test (id UInt32, vec QBit(BFloat16, 4096, 1024)) ENGINE = MergeTree ORDER BY id;
```

هنا تُقسَّم الأبعاد الـ4096 إلى 4 مجموعات، في كل منها 1024 بُعدًا. وتتبع الأعمدة الفرعية ترتيبًا بحسب المجموعات: مع `BFloat16` (16 مستوى بت)، تمثل `vec.1` … `vec.16` مستويات البت الستة عشر لأول مجموعة `stride` (الأبعاد 1–1024)، بينما تنتمي `vec.17` … `vec.32` إلى المجموعة الثانية (الأبعاد 1025–2048)، وهكذا. وبوجه عام، يقرأ `vec.N` مستوى البت `(N-1) % element_size` من مجموعة `stride` رقم `(N-1) / element_size`.

لتشغيل بحث منخفض الأبعاد، مرِّر عدد الأبعاد المطلوب قراءتها بوصفه الوسيط الرابع لدوال المسافة المنقولة (انظر أدناه). ويجب أن يحتوي المتجه المرجعي على هذا العدد من العناصر على الأقل (ويُتجاهل أي عناصر إضافية لاحقة)، كما يجب أن تكون القيمة من مضاعفات `stride`.

<div id="vector-search-functions">
  ## دوال البحث المتجهي
</div>

هذه هي دوال المسافة المستخدمة في البحث عن التشابه المتجهي والتي تستخدم نوع البيانات `QBit`:

* [`L2DistanceTransposed`](/docs/ar/reference/functions/regular-functions/distance-functions#L2DistanceTransposed)
* [`cosineDistanceTransposed`](/docs/ar/reference/functions/regular-functions/distance-functions#cosineDistanceTransposed)
* [`dotProductTransposed`](/docs/ar/reference/functions/regular-functions/distance-functions#dotProductTransposed)

بالنسبة إلى `QBit` ذي stride، تقبل هذه الدوال وسيطًا رابعًا اختياريًا هو `used_dims` — أي عدد الأبعاد الأولى المطلوب قراءتها — بحيث لا تُقرأ إلا مجموعات stride التي تغطي هذه الأبعاد. ويجب أن يحتوي المتجه المرجعي على `used_dims` عنصرًا على الأقل (ويُتجاهل أي عنصر زائد في النهاية، لذا يمكن إعادة استخدام متجه query كامل الحجم في بحث reduced-dimension دون الحاجة إلى اقتطاعه أولًا)، كما يجب أن تكون قيمة `used_dims` مضاعفًا لـ `stride`.
