| إدخال | إخراج | اسم مستعار |
|---|---|---|
| ✔ | ✔ |
الوصف
تنسيق Protobuf هو تنسيق Protocol Buffers.
يتطلب هذا التنسيق مخطط تنسيق خارجيًا، ويُخزَّن مؤقتًا بين الاستعلامات.
يدعم ClickHouse ما يلي:
- صياغتي
proto2وproto3. - الحقول
Repeated/optional/required.
للعثور على المطابقة بين أعمدة الجدول وحقول نوع رسالة Protocol Buffers، يقارن ClickHouse بين أسمائها.
وهذه المقارنة غير حساسة لحالة الأحرف، ويُتعامل مع المحرفين _ (الشرطة السفلية) و. (النقطة) على أنهما متساويان.
إذا اختلف نوع العمود عن نوع الحقل في رسالة Protocol Buffers، فسيُطبَّق التحويل اللازم.
الرسائل المتداخلة مدعومة. على سبيل المثال، بالنسبة إلى الحقل z في نوع الرسالة التالي:
message MessageType {
message XType {
message YType {
int32 z;
};
repeated YType y;
};
XType x;
};يحاول ClickHouse العثور على عمود باسم x.y.z (أو x_y_z أو X.y_Z وما إلى ذلك).
تُعد الرسائل المتداخلة مناسبة للإدخال إلى بُنى البيانات المتداخلة أو للإخراج منها.
بالنسبة إلى الحقول المعيَّنة المفقودة في تنسيق النقل:
- تستخدم الأعمدة المعيَّنة العادية غير القابلة لـ NULL القيمة الافتراضية لحقل مخطط protobuf (
proto2[default = …]، وإلا فالقيمة الافتراضية للنوع) أثناء التحليل، وليس تعبير الجدولDEFAULT. - تأخذ الأعمدة المعيَّنة
Nullable(...)القيمةNULLعند غياب الحقل (ولا تستخدم القيمة الافتراضية لحقل protobuf أو نوعه). - عند تمكين
input_format_protobuf_flatten_google_wrappersلوحدات التغليفgoogle.protobuf.*Value:- تُعامل وحدة التغليف الغائبة في عمود
Nullable(...)كحقل خارجي مفقود وتصبحNULL؛ - تحتفظ وحدة التغليف الموجودة لكنها فارغة (
str {}) بالقيمة الافتراضية العددية المتداخلة (''/0)؛ - يحصل العمود غير القابل لـ NULL المعيَّن إلى وحدة تغليف غائبة على القيمة الافتراضية العددية المتداخلة بدلًا من
NULL.
- تُعامل وحدة التغليف الغائبة في عمود
تنطبق DEFAULT الخاصة بالجدول (وتعبيرات القيمة الافتراضية) على أعمدة الجدول التي ليس لها حقل مطابق في نوع الرسالة عند تمكين input_format_defaults_for_omitted_fields (وهو الإعداد الافتراضي). إذا كان هذا الإعداد 0، تحتفظ الأعمدة غير المعيَّنة بالقيمة الافتراضية لنوع البيانات المُدرجة أثناء التحليل بدلًا من تعبير الجدول DEFAULT.
مثال على قيمة افتراضية لحقل في مخطط proto2 (تُستخدم لحقل معيَّن غائب من الرسالة):
syntax = "proto2";
message MessageType {
optional int32 result_per_page = 3 [default = 10];
}إذا كانت الرسالة تحتوي على oneof وكان input_format_protobuf_oneof_presence مضبوطًا، فإن ClickHouse يملأ العمود الذي يحدّد أيّ حقل ضمن oneof تم العثور عليه.
syntax = "proto3";
message StringOrString {
oneof string_oneof {
string string1 = 1;
string string2 = 42;
}
}CREATE TABLE string_or_string ( string1 String, string2 String, string_oneof Enum('no'=0, 'hello' = 1, 'world' = 42)) Engine=MergeTree ORDER BY tuple();
INSERT INTO string_or_string from INFILE '$CURDIR/data_protobuf/String1' SETTINGS format_schema='$SCHEMADIR/string_or_string.proto:StringOrString' FORMAT ProtobufSingle;
SELECT * FROM string_or_string ┌─────────┬─────────┬──────────────┐
│ string1 │ string2 │ string_oneof │
├─────────┼─────────┼──────────────┤
1. │ │ string2 │ world │
├─────────┼─────────┼──────────────┤
2. │ string1 │ │ hello │
└─────────┴─────────┴──────────────┘يجب أن يكون اسم العمود الذي يشير إلى الوجود هو نفسه اسم oneof.
الرسائل المتداخلة مدعومة (انظر basic-examples). كما أن الرسائل الفارغة مدعومة أيضًا.
الأنواع المسموح بها هي Int8 وUInt8 وInt16 وUInt16 وInt32 وUInt32 وInt64 وUInt64 وEnum وEnum8 أو Enum16.
يجب أن يحتوي Enum (وكذلك Enum8 أو Enum16) على 0 للإشارة إلى الغياب، وعلى وسم كل حالة من oneof لها عمود مطابق في الجدول الهدف، ولا تهم التمثيلات النصية.
بالنسبة إلى أعضاء رسالة oneof الذين ليس لديهم أعمدة جدول مطابقة، يُسمح أيضًا بوسوم Enum المفقودة. إذا كان مثل هذا الفرع موجودًا في الإدخال، يعامل ClickHouse وجود oneof على أنه محذوف ويكتب 0 في عمود الوجود.
يكون الإعداد input_format_protobuf_oneof_presence معطّلًا افتراضيًا
يستقبل ClickHouse رسائل protobuf ويُخرجها بتنسيق محدد بالطول.
وهذا يعني أنه يجب كتابة طول كل رسالة قبلها على هيئة عدد صحيح بعرض متغير (varint).
مثال للاستخدام
قراءة البيانات وكتابتها
في هذا المثال، سنقرأ بعض البيانات من الملف protobuf_message.bin إلى ClickHouse جدول. ثم سنكتبها
مجددًا إلى ملف باسم protobuf_message_from_clickhouse.bin باستخدام format Protobuf.
بالنظر إلى الملف schemafile.proto:
syntax = "proto3";
message MessageType {
string name = 1;
string surname = 2;
uint32 birthDate = 3;
repeated string phoneNumbers = 4;
};إنشاء الملف الثنائي
إذا كنت تعرف بالفعل كيفية تسلسل البيانات وفك تسلسلها بتنسيق Protobuf، فيمكنك تخطي هذه الخطوة.
سنستخدم بايثون لتسلسل بعض البيانات إلى protobuf_message.bin ثم قراءتها في ClickHouse.
إذا كنت تريد استخدام لغة أخرى، فراجع أيضًا: "كيفية قراءة/كتابة رسائل Protobuf المحددة بالطول في اللغات الشائعة".
شغّل الأمر التالي لإنشاء ملف بايثون باسم schemafile_pb2.py في
الدليل نفسه الذي يحتوي على schemafile.proto. يحتوي هذا الملف على فئات بايثون
التي تمثل رسالة UserData من نوع Protobuf:
protoc --python_out=. schemafile.protoالآن، أنشئ ملف بايثون جديدًا باسم generate_protobuf_data.py، في الدليل
نفسه الذي يحتوي على schemafile_pb2.py. الصق فيه الشيفرة التالية:
import schemafile_pb2 # وحدة أنشأها 'protoc'
from google.protobuf import text_format
from google.protobuf.internal.encoder import _VarintBytes # استيراد مُرمِّز varint الداخلي
def create_user_data_message(name, surname, birthDate, phoneNumbers):
"""
ينشئ رسالة UserData من نوع Protobuf ويملؤها بالبيانات.
"""
message = schemafile_pb2.MessageType()
message.name = name
message.surname = surname
message.birthDate = birthDate
message.phoneNumbers.extend(phoneNumbers)
return message
# بيانات مستخدمي المثال
data_to_serialize = [
{"name": "Aisha", "surname": "Khan", "birthDate": 19920815, "phoneNumbers": ["(555) 247-8903", "(555) 612-3457"]},
{"name": "Javier", "surname": "Rodriguez", "birthDate": 20001015, "phoneNumbers": ["(555) 891-2046", "(555) 738-5129"]},
{"name": "Mei", "surname": "Ling", "birthDate": 19980616, "phoneNumbers": ["(555) 956-1834", "(555) 403-7682"]},
]
output_filename = "protobuf_messages.bin"
# افتح الملف الثنائي في وضع الكتابة الثنائية ('wb')
with open(output_filename, "wb") as f:
for item in data_to_serialize:
# أنشئ نسخة رسالة Protobuf للمستخدم الحالي
message = create_user_data_message(
item["name"],
item["surname"],
item["birthDate"],
item["phoneNumbers"]
)
# تسلسل الرسالة
serialized_data = message.SerializeToString()
# الحصول على طول البيانات المُسلسلة
message_length = len(serialized_data)
# استخدم _VarintBytes الداخلي من مكتبة Protobuf لترميز الطول
length_prefix = _VarintBytes(message_length)
# كتابة بادئة الطول
f.write(length_prefix)
# كتابة بيانات الرسالة المُسلسلة
f.write(serialized_data)
print(f"Protobuf messages (length-delimited) written to {output_filename}")
# --- اختياري: التحقق (إعادة القراءة والطباعة) ---
# عند إعادة القراءة، سنستخدم أيضًا decoder الداخلي في Protobuf لقيم varint.
from google.protobuf.internal.decoder import _DecodeVarint32
print("\n--- Verifying by reading back ---")
with open(output_filename, "rb") as f:
buf = f.read() # قراءة الملف بالكامل إلى buffer لتسهيل فك ترميز varint
n = 0
while n < len(buf):
# فك ترميز بادئة طول varint
msg_len, new_pos = _DecodeVarint32(buf, n)
n = new_pos
# استخراج بيانات الرسالة
message_data = buf[n:n+msg_len]
n += msg_len
# تحليل الرسالة
decoded_message = schemafile_pb2.MessageType()
decoded_message.ParseFromString(message_data)
print(text_format.MessageToString(decoded_message, as_utf8=True))الآن شغّل السكربت من سطر الأوامر. يُوصى بتشغيله من
بيئة بايثون افتراضية، على سبيل المثال باستخدام uv:
uv venv proto-venv
source proto-venv/bin/activateستحتاج إلى تثبيت مكتبات بايثون التالية:
uv pip install --upgrade protobufشغّل السكربت لإنشاء الملف الثنائي:
python generate_protobuf_data.pyأنشئ جدول ClickHouse يطابق المخطط:
CREATE DATABASE IF NOT EXISTS test;
CREATE TABLE IF NOT EXISTS test.protobuf_messages (
name String,
surname String,
birthDate UInt32,
phoneNumbers Array(String)
)
ENGINE = MergeTree()
ORDER BY tuple()أدرِج البيانات في الجدول من سطر الأوامر:
cat protobuf_messages.bin | clickhouse-client --query "INSERT INTO test.protobuf_messages SETTINGS format_schema='schemafile:MessageType' FORMAT Protobuf"يمكنك أيضًا كتابة البيانات مرة أخرى في ملف ثنائي باستخدام تنسيق Protobuf:
SELECT * FROM test.protobuf_messages INTO OUTFILE 'protobuf_message_from_clickhouse.bin' FORMAT Protobuf SETTINGS format_schema = 'schemafile:MessageType'باستخدام مخطط Protobuf الخاص بك، يمكنك الآن فك تسلسل البيانات التي كتبها ClickHouse إلى الملف protobuf_message_from_clickhouse.bin.
قراءة البيانات وكتابتها باستخدام ClickHouse Cloud
في ClickHouse Cloud، لا يمكنك تحميل ملف مخطط Protobuf. ومع ذلك، يمكنك استخدام الإعداد format_protobuf_schema
لتحديد المخطَّط داخل الاستعلام. في هذا المثال، نوضّح كيفية قراءة البيانات المُسلسلة من جهازك المحلي
وإدراجها في جدول في ClickHouse Cloud.
كما في المثال السابق، أنشئ الجدول وفقًا لمخطط Protobuf الخاص بك في ClickHouse Cloud:
CREATE DATABASE IF NOT EXISTS test;
CREATE TABLE IF NOT EXISTS test.protobuf_messages (
name String,
surname String,
birthDate UInt32,
phoneNumbers Array(String)
)
ENGINE = MergeTree()
ORDER BY tuple()يحدّد الإعداد format_schema_source مصدر الإعداد format_schema
القيم المحتملة:
- 'file' (الافتراضي): غير مدعوم في Cloud
- 'string': يكون
format_schemaهو المحتوى الحرفي للمخطط. - 'query': يكون
format_schemaاستعلامًا لاسترجاع المخطط.
format_schema_source='string'
لإدراج البيانات في ClickHouse Cloud مع تحديد المخطط على هيئة سلسلة نصية، شغّل:
cat protobuf_messages.bin | clickhouse client --host <hostname> --secure --password <password> --query "INSERT INTO testing.protobuf_messages SETTINGS format_schema_source='syntax = "proto3";message MessageType { string name = 1; string surname = 2; uint32 birthDate = 3; repeated string phoneNumbers = 4;};', format_schema='schemafile:MessageType' FORMAT Protobuf"اعرض البيانات التي أُدرجت في الجدول:
clickhouse client --host <hostname> --secure --password <password> --query "SELECT * FROM testing.protobuf_messages"Aisha Khan 19920815 ['(555) 247-8903','(555) 612-3457']
Javier Rodriguez 20001015 ['(555) 891-2046','(555) 738-5129']
Mei Ling 19980616 ['(555) 956-1834','(555) 403-7682']format_schema_source='query'
يمكنك أيضًا تخزين مخطط Protobuf في جدول.
أنشئ جدولًا على ClickHouse Cloud لإدراج البيانات فيه:
CREATE TABLE testing.protobuf_schema (
schema String
)
ENGINE = MergeTree()
ORDER BY tuple();INSERT INTO testing.protobuf_schema VALUES ('syntax = "proto3";message MessageType { string name = 1; string surname = 2; uint32 birthDate = 3; repeated string phoneNumbers = 4;};');أدرِج البيانات في ClickHouse Cloud، مع تحديد المخطّط في استعلام لتشغيله:
cat protobuf_messages.bin | clickhouse client --host <hostname> --secure --password <password> --query "INSERT INTO testing.protobuf_messages SETTINGS format_schema_source='SELECT schema FROM testing.protobuf_schema', format_schema='schemafile:MessageType' FORMAT Protobuf"اعرض البيانات المُدخلة في الجدول:
clickhouse client --host <hostname> --secure --password <password> --query "SELECT * FROM testing.protobuf_messages"Aisha Khan 19920815 ['(555) 247-8903','(555) 612-3457']
Javier Rodriguez 20001015 ['(555) 891-2046','(555) 738-5129']
Mei Ling 19980616 ['(555) 956-1834','(555) 403-7682']استخدام المخطط المُنشأ تلقائيًا
إذا لم يكن لديك مخطط Protobuf خارجي لبياناتك، فلا يزال بإمكانك إخراج البيانات أو إدخالها بتنسيق Protobuf
باستخدام مخطط مُنشأ تلقائيًا. ولهذا الغرض، استخدم الإعداد format_protobuf_use_autogenerated_schema.
على سبيل المثال:
SELECT * FROM test.hits format Protobuf SETTINGS format_protobuf_use_autogenerated_schema=1في هذه الحالة، سينشئ ClickHouse مخطط Protobuf تلقائيًا استنادًا إلى بنية الجدول باستخدام الدالة
structureToProtobufSchema. ثم سيستخدم هذا المخطط لتسلسل البيانات بتنسيق Protobuf.
يمكنك أيضًا قراءة ملف Protobuf باستخدام المخطط المُنشأ تلقائيًا. في هذه الحالة، يجب أن يكون الملف قد أُنشئ باستخدام المخطط نفسه:
$ cat hits.bin | clickhouse-client --query "INSERT INTO test.hits SETTINGS format_protobuf_use_autogenerated_schema=1 FORMAT Protobuf"يكون الإعداد format_protobuf_use_autogenerated_schema مفعّلًا افتراضيًا، ويُطبَّق إذا لم يتم تعيين format_schema.
يمكنك أيضًا حفظ المخطط المُنشأ تلقائيًا في الملف أثناء الإدخال/الإخراج باستخدام الإعداد output_format_schema. على سبيل المثال:
SELECT * FROM test.hits format Protobuf SETTINGS format_protobuf_use_autogenerated_schema=1, output_format_schema='path/to/schema/schema.proto'في هذه الحالة، سيُحفَظ مخطط Protobuf المُنشأ تلقائيًا في الملف path/to/schema/schema.capnp.
حذف ذاكرة التخزين المؤقت لـ Protobuf
لإعادة تحميل مخطط Protobuf الذي تم تحميله من format_schema_path، استخدم تعليمة SYSTEM DROP ... FORMAT CACHE.
SYSTEM DROP FORMAT SCHEMA CACHE FOR Protobuf