Skip to main content

QueryContexts

ينفّذ ClickHouse Connect الاستعلامات القياسية ضمن QueryContext. يحتوي QueryContext على البُنى الأساسية المستخدمة لبناء الاستعلامات على قاعدة بيانات ClickHouse، بالإضافة إلى التهيئة المستخدمة لمعالجة النتيجة وتحويلها إلى QueryResult أو أي بنية بيانات أخرى خاصة بالاستجابة. ويشمل ذلك الاستعلام نفسه، والمعلمات، والإعدادات، وتنسيقات القراءة، وخصائص أخرى. يمكن الحصول على QueryContext باستخدام الطريقة create_query_context الخاصة بالعميل. تأخذ هذه الطريقة المعلمات نفسها التي تأخذها طريقة الاستعلام الأساسية. ويمكن بعد ذلك تمرير سياق الاستعلام هذا إلى الطرائق query أو query_df أو query_np بوصفه وسيط الكلمة المفتاحية context بدلًا من أي من الوسائط الأخرى الخاصة بتلك الطرائق أو جميعها. لاحظ أن أي وسائط إضافية تُحدَّد عند استدعاء الطريقة ستتجاوز أي خصائص موجودة في QueryContext. أوضح حالة استخدام لـ QueryContext هي إرسال الاستعلام نفسه مع قيم مختلفة لمعاملات الربط. يمكن تحديث جميع قيم المعلمات باستدعاء الطريقة QueryContext.set_parameters مع قاموس، كما يمكن تحديث أي قيمة مفردة باستدعاء QueryContext.set_parameter مع زوج key وvalue المطلوب.
لاحظ أن كائنات QueryContext ليست آمنة للاستخدام المتزامن بين الخيوط، لكن يمكن الحصول على نسخة منها في بيئة متعددة الخيوط عن طريق استدعاء الطريقة QueryContext.updated_copy.

الاستعلامات المتدفقة

يوفّر ClickHouse Connect Client عدة طرائق لاسترجاع البيانات كتدفّق (مُنفَّذ على شكل مولّد في بايثون):
  • query_column_block_stream — يعيد بيانات الاستعلام على شكل كتل، كسلسلة من الأعمدة، باستخدام كائنات بايثون الأصلية
  • query_row_block_stream — يعيد بيانات الاستعلام على شكل كتلة من الصفوف باستخدام كائنات بايثون الأصلية
  • query_rows_stream — يعيد بيانات الاستعلام على شكل سلسلة من الصفوف باستخدام كائنات بايثون الأصلية
  • query_np_stream — يعيد كل كتلة من بيانات الاستعلام في ClickHouse على هيئة مصفوفة NumPy
  • query_df_stream — يعيد كل كتلة من بيانات الاستعلام في ClickHouse على هيئة Pandas DataFrame
  • query_arrow_stream — يعيد بيانات الاستعلام على هيئة PyArrow RecordBlocks
  • query_df_arrow_stream — يعيد كل كتلة من بيانات الاستعلام في ClickHouse على هيئة Pandas DataFrame مدعوم بـ Arrow أو Polars DataFrame، وفقًا للوسيطة المسمّاة dataframe_library (والقيمة الافتراضية هي “pandas”).
تعيد كل واحدة من هذه الطرائق كائن ContextStream، ويجب فتحه باستخدام عبارة with لبدء استهلاك التدفق.

كتل البيانات

يعالج ClickHouse Connect جميع البيانات من طريقة query الأساسية كتدفق من الكتل المستلَمة من خادم ClickHouse. وتُنقل هذه الكتل من ClickHouse وإليه باستخدام التنسيق المخصص “Native”. والـ”كتلة” هي ببساطة تسلسل من أعمدة البيانات الثنائية، بحيث يحتوي كل عمود على عدد متساوٍ من قيم البيانات من نوع البيانات المحدد. (وباعتباره قاعدة بيانات عمودية، يخزّن ClickHouse هذه البيانات بصيغة مشابهة.) ويتحكم في حجم الكتلة المُعادة من الاستعلام إعدادان للمستخدم يمكن تعيينهما على عدة مستويات (ملف تعريف المستخدم، أو المستخدم، أو الجلسة، أو الاستعلام). وهما:
  • max_block_size — حد حجم الكتلة بالصفوف. القيمة الافتراضية 65536.
  • preferred_block_size_bytes — حد مرن لحجم الكتلة بالبايت. القيمة الافتراضية 1,000,0000.
وبصرف النظر عن preferred_block_size_setting، لن تتجاوز أي كتلة أبدًا max_block_size صفًا. واعتمادًا على نوع الاستعلام، قد تكون الكتل الفعلية المُعادة بأي حجم. على سبيل المثال، قد تتضمن الاستعلامات على جدول موزع يغطي عدة أجزاء كتلًا أصغر تُسترجع مباشرةً من كل جزء. عند استخدام إحدى طرق Client ‏query_*_stream، تُعاد النتائج على أساس كتلة تلو الأخرى. ولا يحمّل ClickHouse Connect سوى كتلة واحدة في كل مرة. ويتيح ذلك معالجة كميات كبيرة من البيانات من دون الحاجة إلى تحميل مجموعة نتائج كبيرة بالكامل إلى الذاكرة. لاحظ أنه ينبغي أن يكون التطبيق مستعدًا لمعالجة أي عدد من الكتل، ولا يمكن التحكم في الحجم الدقيق لكل كتلة.

مخزن بيانات HTTP المؤقت عند بطء المعالجة

نظرًا للقيود المفروضة في بروتوكول HTTP، إذا كانت الكتل تُعالَج بمعدل أبطأ بكثير من معدل تدفق البيانات من خادم ClickHouse، فسيغلق خادم ClickHouse الاتصال، ما يؤدي إلى إطلاق استثناء في خيط المعالجة. ويمكن التخفيف من ذلك جزئيًا بزيادة حجم المخزن المؤقت لتدفق HTTP (والذي يبلغ 10 ميغابايت افتراضيًا) باستخدام الإعداد العام http_buffer_size. ولا بأس باستخدام قيم كبيرة لـ http_buffer_size في هذه الحالة إذا كانت هناك ذاكرة كافية متاحة للتطبيق. وتُخزَّن البيانات في المخزن المؤقت بصيغة مضغوطة عند استخدام ضغط lz4 أو zstd، لذا فإن استخدام نوعَي الضغط هذين يزيد إجمالي حجم المخزن المؤقت المتاح.

StreamContexts

تعيد كل واحدة من طرائق query_*_stream (مثل query_row_block_stream) كائن StreamContext من ClickHouse، وهو كائن يجمع في بايثون بين السياق والمولِّد. وهذا هو الاستخدام الأساسي:
لاحظ أن محاولة استخدام StreamContext من دون عبارة with ستؤدي إلى حدوث خطأ. ويضمن استخدام مدير السياق في بايثون إغلاق التدفق (في هذه الحالة، استجابة HTTP متدفقة) إغلاقًا صحيحًا حتى إذا لم تُستهلك جميع البيانات و/أو حدث استثناء أثناء المعالجة. كذلك، لا يمكن استخدام StreamContext لاستهلاك التدفق إلا مرة واحدة. وستؤدي محاولة استخدام StreamContext بعد انتهاء سياقه إلى ظهور StreamClosedError. يمكنك استخدام الخاصية source في StreamContext للوصول إلى الكائن الأصل QueryResult، الذي يتضمن أسماء الأعمدة والأنواع.

أنواع التدفق

تعيد الطريقة query_column_block_stream الكتلة كتسلسل من بيانات الأعمدة المخزّنة كأنواع بيانات بايثون الأصلية. وباستخدام استعلامات taxi_trips المذكورة أعلاه، ستكون البيانات المعادة قائمةً يكون كل عنصر فيها قائمةً أخرى (أو tuple) تحتوي على جميع البيانات الخاصة بالعمود المقابل. لذا سيكون block[0] عبارة عن tuple لا يحتوي إلا على سلاسل نصية. وتُستخدم التنسيقات الموجّهة نحو الأعمدة غالبًا لإجراء عمليات تجميع على جميع القيم في عمود معيّن، مثل جمع إجمالي الأجرة. تعيد الطريقة query_row_block_stream الكتلة كتسلسل من الصفوف، كما في قواعد البيانات العلائقية التقليدية. وبالنسبة إلى رحلات سيارات الأجرة، ستكون البيانات المعادة قائمةً يكون كل عنصر فيها قائمةً أخرى تمثّل صفًا من البيانات. لذا فإن block[0] سيحتوي على جميع الحقول (بالترتيب) الخاصة بأول رحلة سيارة أجرة، بينما سيحتوي block[1] على صف يضم جميع الحقول الخاصة برحلة سيارة الأجرة الثانية، وهكذا. وتُستخدم النتائج الموجّهة نحو الصفوف عادةً في العرض أو عمليات التحويل. تُعد query_row_stream طريقةً ميسّرة تنتقل تلقائيًا إلى الكتلة التالية عند التكرار عبر التدفق. وفيما عدا ذلك، فهي مطابقة تمامًا لـ query_row_block_stream. تعيد الطريقة query_np_stream كل كتلة على شكل مصفوفة NumPy ثنائية الأبعاد. وداخليًا، تُخزَّن مصفوفات NumPy (عادةً) على هيئة أعمدة، لذلك لا حاجة إلى طرق منفصلة للصفوف أو الأعمدة. وسيُعبَّر عن “shape” لمصفوفة NumPy بالشكل (الأعمدة، الصفوف). وتوفّر مكتبة NumPy العديد من الطرق لمعالجة مصفوفات NumPy. لاحظ أنه إذا كانت جميع الأعمدة في الاستعلام تشترك في نفس dtype الخاص بـ NumPy، فستحتوي مصفوفة NumPy المعادة أيضًا على dtype واحد فقط، ويمكن إعادة تشكيلها/تدويرها من دون تغيير بنيتها الداخلية فعليًا. تعيد الطريقة query_df_stream كل كتلة ClickHouse على شكل Pandas DataFrame ثنائي الأبعاد. إليك مثالًا يوضّح أن الكائن StreamContext يمكن استخدامه كسياق بأسلوب مؤجَّل (ولكن مرة واحدة فقط).
تُرجع الطريقة query_df_arrow_stream كل كتلة في ClickHouse على هيئة DataFrame باستخدام الواجهة الخلفية لأنواع البيانات في PyArrow. تدعم هذه الطريقة كلاً من DataFrames في Pandas ‏(2.x أو أحدث) وPolars عبر المعامل dataframe_library (وقيمته الافتراضية "pandas"). وفي كل تكرار، تُنتج DataFrame محوَّلاً من دفعات سجلات PyArrow، مما يوفّر أداءً أفضل وكفاءة أعلى في استخدام الذاكرة لبعض أنواع البيانات. أخيرًا، تُرجع الطريقة query_arrow_stream نتيجة ClickHouse منسَّقة بصيغة ArrowStream على هيئة pyarrow.ipc.RecordBatchStreamReader ومغلَّفة داخل StreamContext. وفي كل تكرار من التدفق، يتم إرجاع PyArrow RecordBlock.

أمثلة على التدفق

تدفق الصفوف

تمرير كتل الصفوف

تدفق Pandas DataFrames

تدفق دفعات Arrow

استعلامات NumPy وPandas وArrow

يوفّر ClickHouse Connect طريقة استعلام متخصصة للعمل مع بُنى بيانات NumPy وPandas وArrow. تتيح لك هذه الطريقة استرداد نتائج الاستعلام مباشرةً بهذه التنسيقات الشائعة للبيانات من دون تحويل يدوي.

استعلامات NumPy

تُرجِع الطريقة query_np نتائج الاستعلام على شكل مصفوفة NumPy بدلًا من كائن QueryResult من ClickHouse Connect.

استعلامات Pandas

تعيد الطريقة query_df نتائج الاستعلام في صورة Pandas DataFrame بدلًا من QueryResult من ClickHouse Connect.

استعلامات PyArrow

تعيد الطريقة query_arrow نتائج الاستعلام على شكل PyArrow Table. وهي تستخدم تنسيق Arrow في ClickHouse مباشرةً، لذا فهي لا تقبل سوى ثلاث وسيطات مشتركة مع الطريقة الرئيسية query: query وparameters وsettings. بالإضافة إلى ذلك، توجد وسيطة إضافية هي use_strings، وتحدد ما إذا كان Arrow Table سيعرض أنواع String في ClickHouse كسلاسل نصية (إذا كانت True) أو كبايتات (إذا كانت False).

DataFrames المستندة إلى Arrow

يدعم ClickHouse Connect إنشاء DataFrame بسرعة وكفاءة في استخدام الذاكرة من نتائج Arrow عبر الطريقتين query_df_arrow وquery_df_arrow_stream. وهاتان الطريقتان مجرد غلافين خفيفين حول طريقتي استعلام Arrow، وتُجريان تحويلات إلى DataFrames من دون نسخ حيثما أمكن:
  • query_df_arrow: ينفّذ الاستعلام باستخدام تنسيق الإخراج Arrow في ClickHouse ويُرجع DataFrame.
    • بالنسبة إلى dataframe_library='pandas'، يُرجع DataFrame من pandas 2.x باستخدام أنواع بيانات مستندة إلى Arrow (pd.ArrowDtype). ويتطلب ذلك pandas 2.x، ويستفيد من المخازن المؤقتة من دون نسخ حيثما أمكن لتحقيق أداء ممتاز وعبء منخفض على الذاكرة.
    • بالنسبة إلى dataframe_library='polars'، يُرجع DataFrame من Polars مُنشأ من جدول Arrow (pl.from_arrow)، وهو بالكفاءة نفسها تقريبًا، ويمكن أن يكون من دون نسخ بحسب البيانات.
  • query_df_arrow_stream: يبث النتائج كتسلسل من DataFrames ‏(pandas 2.x أو Polars) مُحوَّلة من دفعات تدفق Arrow.

استعلام إلى DataFrame مستند إلى Arrow

ملاحظات ومحاذير

  • تعيين أنواع Arrow: عند إرجاع البيانات بتنسيق Arrow، يطابق ClickHouse الأنواع مع أقرب أنواع Arrow مدعومة. بعض أنواع ClickHouse لا تملك مقابلًا أصليًا في Arrow، لذا تُعاد كبايتات خام في حقول Arrow (عادةً BINARY أو FIXED_SIZE_BINARY).
    • أمثلة: يُمثَّل IPv4 كـ Arrow UINT32؛ أما IPv6 والأعداد الصحيحة الكبيرة (Int128/UInt128/Int256/UInt256) فغالبًا ما تُمثَّل كـ FIXED_SIZE_BINARY/BINARY مع بايتات خام.
    • في هذه الحالات، سيحتوي عمود DataFrame على قيم بايتية مستندة إلى حقل Arrow؛ وتقع على عاتق شيفرة العميل مسؤولية تفسير هذه البايتات أو تحويلها وفقًا لدلالات ClickHouse.
  • لا تُخرَج أنواع بيانات Arrow غير المدعومة (مثل UUID/ENUM كأنواع Arrow فعلية)؛ وبدلًا من ذلك، تُمثَّل القيم باستخدام أقرب نوع Arrow مدعوم (وغالبًا كبايتات ثنائية) في المخرجات.
  • متطلب Pandas: تتطلب dtypes المستندة إلى Arrow إصدار pandas 2.x. بالنسبة إلى إصدارات pandas الأقدم، استخدم query_df (غير Arrow) بدلًا من ذلك.
  • Strings مقابل الثنائي: يتحكم الخيار use_strings (عندما يكون مدعومًا بواسطة إعداد الخادم output_format_arrow_string_as_string) في ما إذا كانت الأعمدة من نوع ClickHouse String ستُعاد كسلاسل Arrow أو كبيانات ثنائية.

أمثلة على تحويل الأنواع غير المتطابقة بين ClickHouse وArrow

عندما يعيد ClickHouse الأعمدة على هيئة بيانات ثنائية خام (مثل FIXED_SIZE_BINARY أو BINARY)، تكون مسؤولية شيفرة التطبيق تحويل هذه البايتات إلى أنواع بايثون المناسبة. توضّح الأمثلة أدناه أن بعض التحويلات يمكن تنفيذها باستخدام واجهات برمجة تطبيقات مكتبة DataFrame، بينما قد يتطلب بعضها الآخر أساليب pure Python مثل struct.unpack (وهي تضحي بالأداء لكنها تحافظ على المرونة). قد تصل أعمدة Date بصيغة UINT16 (عدد الأيام منذ حقبة Unix، 1970‑01‑01). ويكون التحويل داخل DataFrame فعّالًا ومباشرًا:
قد تصل أعمدة مثل Int128 بصيغة FIXED_SIZE_BINARY على شكل بايتات خام. ويوفّر Polars دعمًا مباشرًا للأعداد الصحيحة ذات 128 بت:
اعتبارًا من الإصدار 2.3 من NumPy، لا يتوفر dtype عام لعدد صحيح بطول 128 بت، لذا نضطر إلى الاعتماد على بايثون فقط، ويمكننا إجراء شيء مثل:
الخلاصة: يجب أن تتعامل شيفرة التطبيق مع هذه التحويلات وفقًا لإمكانات مكتبة DataFrame المختارة ومقايضات الأداء المقبولة. وعندما لا تتوفر تحويلات أصلية لـ DataFrame، تظل الأساليب المعتمدة على بايثون الصرف خيارًا متاحًا.

تنسيقات القراءة

تتحكم تنسيقات القراءة في أنواع بيانات القيم المُعادة من طرق query وquery_np وquery_df في العميل. (أما raw_query وquery_arrow فلا يغيّران البيانات الواردة من ClickHouse، لذا لا ينطبق عليهما التحكم في التنسيق.) على سبيل المثال، إذا جرى تغيير تنسيق القراءة لمعرّف UUID من التنسيق native الافتراضي إلى التنسيق البديل string، فسيُعاد استعلام ClickHouse لعمود UUID على شكل قيم نصية (باستخدام تنسيق RFC 1422 القياسي 8-4-4-4-12) بدلًا من كائنات UUID في بايثون. يمكن أن تتضمن وسيطة “نوع البيانات” لأي دالة تنسيق محارف بديلة. ويكون التنسيق عبارة عن سلسلة نصية واحدة بأحرف صغيرة. يمكن تعيين تنسيقات القراءة على عدة مستويات:
  • على المستوى العام، باستخدام الطرق المعرّفة في حزمة clickhouse_connect.datatypes.format. سيتحكم ذلك في تنسيق نوع البيانات المُكوَّن لجميع الاستعلامات.
  • للاستعلام بالكامل، باستخدام وسيطة القاموس الاختيارية query_formats. في هذه الحالة، سيستخدم أي عمود (أو عمود فرعي) من أنواع البيانات المحددة التنسيق المُهيأ.
  • بالنسبة إلى القيم في عمود معيّن، باستخدام وسيطة القاموس الاختيارية column_formats. يكون المفتاح هو اسم العمود كما يعيده ClickHouse، وتكون القيمة إما تنسيقًا لعمود البيانات أو قاموس “format” من المستوى الثاني يحتوي على اسم نوع في ClickHouse وقيمة من تنسيقات الاستعلام. يمكن استخدام هذا القاموس الثانوي مع أنواع الأعمدة المتداخلة مثل Tuples أو Maps.

خيارات تنسيق القراءة (أنواع بايثون)

البيانات الخارجية

يمكن لاستعلامات ClickHouse قبول بيانات خارجية بأي تنسيق من تنسيقات ClickHouse. تُرسل هذه البيانات الثنائية مع سلسلة الاستعلام لاستخدامها في معالجة البيانات. تجد تفاصيل ميزة البيانات الخارجية هنا. تقبل طرائق query* في العميل معلمة اختيارية باسم external_data للاستفادة من هذه الميزة. يجب أن تكون قيمة المعلمة external_data كائنًا من نوع clickhouse_connect.driver.external.ExternalData. يقبل مُنشئ هذا الكائن الوسيطات التالية: لإرسال استعلام مع ملف CSV خارجي يحتوي على بيانات “movie”، ودمج هذه البيانات مع جدول directors الموجود مسبقًا على خادم ClickHouse:
يمكن إضافة ملفات بيانات خارجية إضافية إلى كائن ExternalData الأولي باستخدام الطريقة add_file، التي تأخذ المعلمات نفسها التي يأخذها المُنشئ. بالنسبة إلى HTTP، تُرسَل جميع البيانات الخارجية كجزء من رفع ملف بصيغة multi-part/form-data.

المناطق الزمنية

توجد عدة آليات لتطبيق منطقة زمنية على قيم ClickHouse من نوعي DateTime وDateTime64. داخليًا، يخزّن خادم ClickHouse دائمًا أي كائن DateTime أو DateTime64 على شكل رقم غير مرتبط بمنطقة زمنية يمثّل عدد الثواني منذ epoch، أي 1970-01-01 00:00:00 بتوقيت UTC. وبالنسبة إلى قيم DateTime64، قد يكون هذا التمثيل بالمللي ثانية أو الميكروثانية أو النانوثانية منذ epoch، وذلك حسب precision. ونتيجة لذلك، فإن تطبيق أي معلومات خاصة بالمنطقة الزمنية يحدث دائمًا على جهة العميل. لاحظ أن هذا يتطلب عمليات حسابية إضافية ملحوظة، لذا يُنصح في التطبيقات الحساسة للأداء بالتعامل مع أنواع DateTime على أنها timestamps منذ epoch، باستثناء العرض للمستخدم والتحويل (فعلى سبيل المثال، تكون Pandas Timestamps دائمًا عددًا صحيحًا من 64 بت يمثّل نانوثواني epoch لتحسين الأداء). عند استخدام أنواع بيانات مرتبطة بمنطقة زمنية في الاستعلامات، وبخاصة كائن Python ‏datetime.datetime، يطبّق clickhouse-connect منطقة زمنية على جهة العميل وفق قواعد الأسبقية التالية:
  1. إذا جرى تحديد parameter للأسلوب query باسم client_tzs لهذا query، فستُطبَّق المنطقة الزمنية المحددة للعمود
  2. إذا كان عمود ClickHouse يتضمن metadata للمنطقة الزمنية (أي إذا كان من نوع مثل DateTime64(3, ‘America/Denver’))، فستُطبَّق المنطقة الزمنية الخاصة بعمود ClickHouse. (لاحظ أن metadata هذه للمنطقة الزمنية غير متاحة لـ clickhouse-connect لأعمدة DateTime قبل إصدار ClickHouse 23.2)
  3. إذا جرى تحديد parameter للأسلوب query باسم query_tz لهذا query، فستُطبَّق “المنطقة الزمنية الخاصة بالاستعلام”.
  4. إذا طُبِّق إعداد timezone على query أو session، فستُطبَّق تلك المنطقة الزمنية. (هذه الوظيفة لم تُطرح بعد في خادم ClickHouse)
  5. وأخيرًا، إذا كانت parameter ‏apply_server_timezone للعميل مضبوطة على True (وهو الإعداد الافتراضي)، فستُطبَّق server timezone الخاصة بـ ClickHouse.
لاحظ أنه إذا كانت المنطقة الزمنية المطبقة وفق هذه القواعد هي UTC، فإن clickhouse-connect سيُرجِع دائمًا كائن Python من النوع datetime.datetime غير مرتبط بمنطقة زمنية. ويمكن بعد ذلك إضافة معلومات منطقة زمنية إضافية إلى هذا الكائن غير المرتبط بمنطقة زمنية من خلال شيفرة التطبيق إذا لزم الأمر.
آخر تعديل في ٢٣ يوليو ٢٠٢٦