الانتقال إلى المحتوى الرئيسي

استراتيجية التشغيل المتوازي

عند الانتقال من Elastic إلى ClickStack في حالات استخدام رصد، نوصي باتباع نهج التشغيل المتوازي بدلًا من محاولة ترحيل البيانات التاريخية. توفّر هذه الاستراتيجية عدة مزايا:
  1. أدنى قدر من المخاطر: من خلال تشغيل النظامين بالتوازي، تحافظ على إمكانية الوصول إلى البيانات الحالية ولوحات المعلومات، مع اختبار ClickStack وتعويد المستخدمين على النظام الجديد.
  2. انقضاء البيانات بشكل طبيعي: تكون لمعظم بيانات رصد مدة احتفاظ محدودة (عادةً 30 يومًا أو أقل)، مما يتيح انتقالًا طبيعيًا مع انقضاء البيانات من Elastic.
  3. ترحيل أكثر بساطة: لا حاجة إلى أدوات أو عمليات معقدة لنقل البيانات التاريخية بين الأنظمة.

ترحيل البياناتنعرض نهجًا لترحيل البيانات الأساسية من Elasticsearch إلى ClickHouse في قسم “ترحيل البيانات”. لا ينبغي استخدام هذا النهج مع مجموعات البيانات الكبيرة، لأنه نادرًا ما يوفّر أداءً جيدًا، إذ تحدّه قدرة Elasticsearch على التصدير بكفاءة، مع دعم تنسيق JSON فقط.

خطوات التنفيذ

1

تهيئة الإدخال المزدوج

اضبط pipeline جمع البيانات لديك لإرسال البيانات إلى كلٍّ من Elastic وClickStack في الوقت نفسه.وتعتمد طريقة تنفيذ ذلك على الوكلاء الذين تستخدمهم حاليًا لعملية الجمع — راجع “ترحيل الوكلاء”.
2

ضبط فترات الاحتفاظ

هيّئ إعدادات TTL في Elastic بما يتوافق مع فترة الاحتفاظ المطلوبة. ثم اضبط TTL في ClickStack للاحتفاظ بالبيانات للمدة نفسها.
3

التحقق والمقارنة

  • شغّل استعلامات على كلا النظامين للتأكد من اتساق البيانات
  • قارن أداء الاستعلامات والنتائج
  • انقل لوحات المعلومات والتنبيهات إلى ClickStack. هذه العملية يدوية حاليًا.
  • تحقّق من أن جميع لوحات المعلومات والتنبيهات المهمة تعمل كما هو متوقع في ClickStack
4

الانتقال التدريجي

  • مع انتهاء صلاحية البيانات في Elastic بشكل طبيعي، ستعتمد تدريجيًا على ClickStack بصورة أكبر
  • وبعد ترسخ الثقة في ClickStack، يمكنك البدء في إعادة توجيه الاستعلامات ولوحات المعلومات

الاحتفاظ طويل الأمد

بالنسبة إلى المؤسسات التي تحتاج إلى فترات احتفاظ أطول:
  • واصل تشغيل النظامين بالتوازي إلى أن تنتهي مدة احتفاظ جميع البيانات في Elastic
  • يمكن أن تساعد إمكانات ClickStack الخاصة بـالتخزين المتدرج في إدارة البيانات طويلة الأمد بكفاءة.
  • فكّر في استخدام العروض المادية للاحتفاظ بالبيانات التاريخية المجمّعة أو المُرشَّحة، مع السماح بانتهاء صلاحية البيانات الخام.

الجدول الزمني للترحيل

يعتمد الجدول الزمني للترحيل على متطلبات الاحتفاظ بالبيانات لديك:
  • الاحتفاظ لمدة 30 يومًا: يمكن إتمام الترحيل خلال شهر.
  • الاحتفاظ لمدة أطول: استمر في التشغيل المتوازي حتى تنقضي مدة الاحتفاظ بالبيانات في Elastic.
  • البيانات التاريخية: إذا كانت هناك ضرورة قصوى، ففكّر في استخدام ترحيل البيانات لاستيراد بيانات تاريخية محددة.

ترحيل الإعدادات

عند الترحيل من Elastic إلى ClickStack، ستحتاج إلى تكييف إعدادات الفهرسة والتخزين لديك بما يلائم معمارية ClickHouse. فبينما يعتمد Elasticsearch على التوسّع الأفقي والتجزئة لتحقيق الأداء وتحمّل الأعطال، ولذلك يستخدم عدة shards افتراضيًا، فإن ClickHouse مُحسَّن للتوسّع الرأسي، وعادةً ما يحقق أفضل أداء مع عدد أقل من shards. نوصي بالبدء بـ shard واحد والتوسّع رأسيًا. هذا الإعداد مناسب لمعظم أعباء عمل رصد، ويُبسّط الإدارة وضبط أداء الاستعلامات.
  • ClickHouse Cloud: يستخدم افتراضيًا معمارية shard واحد مع عدة نسخ متماثلة. ويتوسّع كل من التخزين والقدرة الحاسوبية بشكل مستقل، مما يجعله مثاليًا لحالات استخدام رصد ذات أنماط استيعاب غير متوقعة وأعباء العمل التي تتركز على القراءة.
  • ClickHouse OSS: في عمليات النشر المُدارة ذاتيًا، نوصي بما يلي:
    • البدء بـ shard واحد
    • التوسّع رأسيًا بإضافة CPU وRAM
    • استخدام تخزين متدرج لتوسيع القرص المحلي باستخدام تخزين كائنات متوافق مع S3
    • استخدام ReplicatedMergeTree إذا كان التوافر العالي مطلوبًا
    • لتحقيق تحمّل الأعطال، تكون نسخة متماثلة واحدة من الـ shard كافية عادةً في أعباء عمل رصد.

متى تحتاج إلى التجزئة

قد تكون التجزئة ضرورية إذا:
  • تجاوز معدل إدخال البيانات لديك سعة عقدة واحدة (عادةً >500K صف/ثانية)
  • كنت بحاجة إلى عزل المستأجرين أو فصل البيانات حسب المنطقة
  • كانت مجموعة بياناتك الإجمالية كبيرة جدًا بالنسبة إلى خادم واحد، حتى مع تخزين الكائنات
إذا كنت بحاجة فعلًا إلى التجزئة، فارجع إلى التوسّع الأفقي للحصول على إرشادات حول مفاتيح التجزئة وإعداد الجدول الموزّع.

الاحتفاظ بالبيانات وTTL

يستخدم ClickHouse عبارات TTL في جداول MergeTree لإدارة انتهاء صلاحية البيانات. ويمكن لسياسات TTL أن:
  • تحذف البيانات منتهية الصلاحية تلقائيًا
  • تنقل البيانات الأقدم إلى تخزين كائني بارد
  • تحتفظ فقط بالسجلات الحديثة كثيرة الاستعلام على قرص سريع
نوصي بمواءمة إعدادات TTL في ClickHouse مع سياسات الاحتفاظ الحالية في Elastic للحفاظ على دورة حياة متسقة للبيانات أثناء الترحيل. للاطلاع على أمثلة، راجع إعداد TTL لبيئة الإنتاج في ClickStack.

ترحيل البيانات

مع أننا نوصي بالتشغيل المتوازي لمعظم بيانات الرصد، فهناك حالات محددة قد تستلزم ترحيل البيانات مباشرةً من Elasticsearch إلى ClickHouse:
  • جداول بحث صغيرة تُستخدم في إثراء البيانات (مثل تعيينات المستخدمين وكتالوجات الخدمات)
  • بيانات أعمال مخزنة في Elasticsearch تحتاج إلى ربطها ببيانات الرصد، إذ تجعل إمكانات SQL في ClickHouse وتكاملات ذكاء الأعمال صيانة البيانات والاستعلام عنها أسهل مقارنةً بخيارات الاستعلام الأكثر محدودية في Elasticsearch.
  • بيانات التهيئة التي يجب الحفاظ عليها أثناء الترحيل
لا يكون هذا النهج عمليًا إلا مع مجموعات البيانات التي تقل عن 10 ملايين صف، لأن إمكانات التصدير في Elasticsearch تقتصر على JSON عبر HTTP ولا تتوسع جيدًا مع مجموعات البيانات الأكبر. تتيح الخطوات التالية ترحيل فهرس Elasticsearch واحد باستخدام ClickHouse.
1

ترحيل المخطط

أنشئ جدولاً في ClickHouse للفهرس المُراد ترحيله من Elasticsearch. يمكنك تعيين أنواع Elasticsearch إلى ما يقابلها في ClickHouse. وبدلاً من ذلك، يمكنك الاعتماد على نوع بيانات JSON في ClickHouse، الذي سيُنشئ تلقائياً أعمدةً بالنوع المناسب عند إدراج البيانات.خذ بعين الاعتبار تعيين Elasticsearch التالي لفهرس يحتوي على بيانات syslog:
GET .ds-logs-system.syslog-default-2025.06.03-000001/_mapping
{
  ".ds-logs-system.syslog-default-2025.06.03-000001": {
    "mappings": {
      "_meta": {
        "managed_by": "fleet",
        "managed": true,
        "package": {
          "name": "system"
        }
      },
      "_data_stream_timestamp": {
        "enabled": true
      },
      "dynamic_templates": [],
      "date_detection": false,
      "properties": {
        "@timestamp": {
          "type": "date",
          "ignore_malformed": false
        },
        "agent": {
          "properties": {
            "ephemeral_id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "name": {
              "type": "keyword",
              "fields": {
                "text": {
                  "type": "match_only_text"
                }
              }
            },
            "type": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "version": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "cloud": {
          "properties": {
            "account": {
              "properties": {
                "id": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "availability_zone": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "image": {
              "properties": {
                "id": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "instance": {
              "properties": {
                "id": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "machine": {
              "properties": {
                "type": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "provider": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "region": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "service": {
              "properties": {
                "name": {
                  "type": "keyword",
                  "fields": {
                    "text": {
                      "type": "match_only_text"
                    }
                  }
                }
              }
            }
          }
        },
        "data_stream": {
          "properties": {
            "dataset": {
              "type": "constant_keyword",
              "value": "system.syslog"
            },
            "namespace": {
              "type": "constant_keyword",
              "value": "default"
            },
            "type": {
              "type": "constant_keyword",
              "value": "logs"
            }
          }
        },
        "ecs": {
          "properties": {
            "version": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "elastic_agent": {
          "properties": {
            "id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "snapshot": {
              "type": "boolean"
            },
            "version": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "event": {
          "properties": {
            "agent_id_status": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "dataset": {
              "type": "constant_keyword",
              "value": "system.syslog"
            },
            "ingested": {
              "type": "date",
              "format": "strict_date_time_no_millis||strict_date_optional_time||epoch_millis",
              "ignore_malformed": false
            },
            "module": {
              "type": "constant_keyword",
              "value": "system"
            },
            "timezone": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "host": {
          "properties": {
            "architecture": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "containerized": {
              "type": "boolean"
            },
            "hostname": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "ip": {
              "type": "ip"
            },
            "mac": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "name": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "os": {
              "properties": {
                "build": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "codename": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "family": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "kernel": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "name": {
                  "type": "keyword",
                  "fields": {
                    "text": {
                      "type": "match_only_text"
                    }
                  }
                },
                "platform": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "type": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "version": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            }
          }
        },
        "input": {
          "properties": {
            "type": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "log": {
          "properties": {
            "file": {
              "properties": {
                "path": {
                  "type": "keyword",
                  "fields": {
                    "text": {
                      "type": "match_only_text"
                    }
                  }
                }
              }
            },
            "offset": {
              "type": "long"
            }
          }
        },
        "message": {
          "type": "match_only_text"
        },
        "process": {
          "properties": {
            "name": {
              "type": "keyword",
              "fields": {
                "text": {
                  "type": "match_only_text"
                }
              }
            },
            "pid": {
              "type": "long"
            }
          }
        },
        "system": {
          "properties": {
            "syslog": {
              "type": "object"
            }
          }
        }
      }
    }
  }
}
مخطط جدول ClickHouse المقابل:
SET enable_json_type = 1;

CREATE TABLE logs_system_syslog
(
    `@timestamp` DateTime,
    `agent` Tuple(
        ephemeral_id String,
        id String,
        name String,
        type String,
        version String),
    `cloud` Tuple(
        account Tuple(
            id String),
        availability_zone String,
        image Tuple(
            id String),
        instance Tuple(
            id String),
        machine Tuple(
            type String),
        provider String,
        region String,
        service Tuple(
            name String)),
    `data_stream` Tuple(
        dataset String,
        namespace String,
        type String),
    `ecs` Tuple(
        version String),
    `elastic_agent` Tuple(
        id String,
        snapshot UInt8,
        version String),
    `event` Tuple(
        agent_id_status String,
        dataset String,
        ingested DateTime,
        module String,
        timezone String),
    `host` Tuple(
        architecture String,
        containerized UInt8,
        hostname String,
        id String,
        ip Array(Variant(IPv4, IPv6)),
        mac Array(String),
        name String,
        os Tuple(
            build String,
            codename String,
            family String,
            kernel String,
            name String,
            platform String,
            type String,
            version String)),
    `input` Tuple(
        type String),
    `log` Tuple(
        file Tuple(
            path String),
        offset Int64),
    `message` String,
    `process` Tuple(
        name String,
        pid Int64),
    `system` Tuple(
        syslog JSON)
)
ENGINE = MergeTree
ORDER BY (`host.name`, `@timestamp`)
تجدر الإشارة إلى أن:
  • تُستخدم Tuples لتمثيل الهياكل المتداخلة بدلًا من صيغة النقطة
  • استخدم أنواع ClickHouse المناسبة وفقًا للتعيين:
    • keywordString
    • dateDateTime
    • booleanUInt8
    • longInt64
    • ipArray(Variant(IPv4, IPv6)). نستخدم Variant(IPv4, IPv6) هنا لأن الحقل يحتوي على مزيج من IPv4 وIPv6.
    • objectJSON لكائن syslog ذي البنية غير المتوقعة.
  • العمودان host.ip وhost.mac من نوع Array صراحةً، بخلاف Elasticsearch حيث تكون جميع الأنواع مصفوفات.
  • تُضاف عبارة ORDER BY باستخدام الطابع الزمني واسم المضيف لتحسين كفاءة الاستعلامات المعتمدة على الوقت
  • يُستخدم MergeTree، وهو الأنسب لبيانات السجلات، كنوع المحرّك
يُعدّ هذا الأسلوب القائم على تعريف المخطط بصورة ثابتة واستخدام نوع JSON بشكل انتقائي حيثما دعت الحاجة مُوصى به.يتمتع هذا المخطط الصارم بعدد من المزايا:
  • التحقق من صحة البيانات – إن فرض مخطط صارم يتجنب خطر تضخم الأعمدة خارج البُنى المحددة.
  • تجنب خطر تضخم الأعمدة: رغم أن نوع JSON يمكن أن يتوسع إلى آلاف الأعمدة المحتملة، حيث تُخزَّن الأعمدة الفرعية كأعمدة مخصصة، فقد يؤدي ذلك إلى تضخم ملفات الأعمدة، إذ يُنشأ عدد مفرط من ملفات الأعمدة بما يؤثر في الأداء. وللتخفيف من ذلك، يوفّر نوع Dynamic الأساسي الذي يستخدمه JSON معامِل max_dynamic_paths، الذي يحدّ من عدد المسارات الفريدة المخزنة كملفات أعمدة منفصلة. وبمجرد بلوغ الحد، تُخزَّن المسارات الإضافية في ملف أعمدة مشترك باستخدام تنسيق مُرمَّز مضغوط، مما يحافظ على الأداء وكفاءة التخزين مع دعم مرونة استيعاب البيانات. ومع ذلك، فإن الوصول إلى ملف الأعمدة المشترك هذا لا يقدّم المستوى نفسه من الأداء. وتجدر الإشارة أيضًا إلى أنه يمكن استخدام عمود JSON مع تلميحات الأنواع. وستقدّم الأعمدة “المُشار إليها” الأداء نفسه الذي تقدمه الأعمدة المخصصة.
  • استبطان أبسط للمسارات والأنواع: رغم أن نوع JSON يدعم دوال الاستبطان لتحديد الأنواع والمسارات التي جرى استنتاجها، فإن البُنى الثابتة قد تكون أسهل في الاستكشاف، على سبيل المثال باستخدام DESCRIBE.

بدلاً من ذلك، يمكنك ببساطة إنشاء جدول يحتوي على عمود JSON واحد.
SET enable_json_type = 1;

CREATE TABLE syslog_json
(
 `json` JSON(`host.name` String, `@timestamp` DateTime)
)
ENGINE = MergeTree
ORDER BY (`json.host.name`, `json.@timestamp`)
نوفّر تلميحًا للنوع للعمودين host.name وtimestamp في تعريف JSON لأننا نستخدمهما في الترتيب/المفتاح الأساسي. يساعد ذلك ClickHouse على معرفة أن هذين العمودين لن تكون قيمتهما null، ويضمن أيضًا معرفة الأعمدة الفرعية التي يجب استخدامها (إذ قد توجد عدة أعمدة فرعية لكل نوع، ما يجعل الأمر ملتبسًا لولا ذلك).
هذا النهج الأخير، وإن كان أبسط، فهو الأنسب لمهام النمذجة الأولية وهندسة البيانات. أما في بيئات الإنتاج، فاستخدم JSON فقط للبنى الفرعية الديناميكية عند الضرورة.لمزيد من التفاصيل حول استخدام نوع JSON في المخططات وكيفية تطبيقه بكفاءة، نوصي بالرجوع إلى الدليل “تصميم مخططك”.
2

ثبّت elasticdump

نوصي باستخدام elasticdump لتصدير البيانات من Elasticsearch. تتطلب هذه الأداة node، ويجب تثبيتها على جهاز يتمتع بقرب شبكي من كلٍّ من Elasticsearch وClickHouse. نوصي باستخدام خادم مخصّص يحتوي على 4 أنوية على الأقل و16GB من RAM لمعظم عمليات التصدير.
npm install elasticdump -g
يوفّر elasticdump عدة مزايا لترحيل البيانات:
  • يتفاعل مباشرةً مع واجهة برمجة تطبيقات REST الخاصة بـ Elasticsearch، مما يضمن تصدير البيانات على نحو صحيح.
  • يحافظ على اتساق البيانات أثناء عملية التصدير باستخدام واجهة برمجة تطبيقات Point-in-Time ‏(PIT) — ما ينشئ لقطة متسقة للبيانات في لحظة زمنية محددة.
  • يصدّر البيانات مباشرةً بتنسيق JSON، ويمكن تمريرها كتدفّق إلى clickhouse client لإدراجها.
حيثما أمكن، نوصي بتشغيل ClickHouse وElasticsearch وelastic dump جميعها ضمن منطقة التوفّر نفسها أو مركز البيانات نفسه لتقليل حركة البيانات الصادرة عبر الشبكة إلى الحد الأدنى وزيادة معدل النقل إلى الحد الأقصى.
3

تثبيت عميل ClickHouse

تأكد من أنّ ClickHouse مثبّت على الخادم الذي يوجد عليه elasticdump. لا تشغّل خادم ClickHouse — فهذه الخطوات لا تتطلب سوى العميل.
4

دفق البيانات

لدفق البيانات بين Elasticsearch وClickHouse، استخدم الأمر elasticdump مع توجيه المخرجات مباشرةً إلى clickhouse client. يقوم ما يلي بإدراج البيانات في جدولنا المنظَّم جيدًا logs_system_syslog.
# export url and credentials
export ELASTICSEARCH_INDEX=.ds-logs-system.syslog-default-2025.06.03-000001
export ELASTICSEARCH_URL=
export ELASTICDUMP_INPUT_USERNAME=
export ELASTICDUMP_INPUT_PASSWORD=
export CLICKHOUSE_HOST=
export CLICKHOUSE_PASSWORD=
export CLICKHOUSE_USER=default

# command to run - modify as required
elasticdump --input=${ELASTICSEARCH_URL} --type=data --input-index ${ELASTICSEARCH_INDEX} --output=$ --sourceOnly --searchAfter --pit=true | 
clickhouse-client --host ${CLICKHOUSE_HOST} --secure --password ${CLICKHOUSE_PASSWORD} --user ${CLICKHOUSE_USER} --max_insert_block_size=1000 \
--min_insert_block_size_bytes=0 --min_insert_block_size_rows=1000 --query="INSERT INTO test.logs_system_syslog FORMAT JSONEachRow"
لاحظ استخدام العلامات التالية مع elasticdump:
  • type=data - يقيّد الاستجابة بحيث تقتصر على محتوى المستند فقط في Elasticsearch.
  • input-index - فهرس الإدخال لدينا في Elasticsearch.
  • output=$ - يعيد توجيه جميع النتائج إلى stdout.
  • العلامة sourceOnly تضمن حذف حقول البيانات الوصفية من الاستجابة.
  • العلامة searchAfter لاستخدام searchAfter API من أجل ترقيم صفحات النتائج بكفاءة.
  • pit=true لضمان الحصول على نتائج متسقة بين الاستعلامات باستخدام point in time API.

معلمات عميل ClickHouse هنا (باستثناء بيانات الاعتماد):
  • max_insert_block_size=1000 - سيرسل عميل ClickHouse البيانات بمجرد الوصول إلى هذا العدد من الصفوف. تؤدي زيادته إلى تحسين معدل النقل، لكن على حساب الوقت اللازم لتجميع كتلة، مما يعني زيادة الوقت قبل ظهور البيانات في ClickHouse.
  • min_insert_block_size_bytes=0 - يعطّل دمج الكتل في الخادم حسب عدد البايتات.
  • min_insert_block_size_rows=1000 - يدمج الكتل القادمة من العملاء على جانب الخادم. في هذه الحالة، نضبطه على max_insert_block_size بحيث تظهر الصفوف فورًا. زِد هذه القيمة لتحسين معدل النقل.
  • query="INSERT INTO logs_system_syslog FORMAT JSONAsRow" - إدراج البيانات بتنسيق JSONEachRow format. وهذا مناسب عند الإرسال إلى مخطط محدد بوضوح مثل logs_system_syslog.

يمكنك توقّع معدل نقل في حدود آلاف الصفوف في الثانية.
الإدراج في صف JSON واحدإذا كنت تُدرج في عمود JSON واحد (راجع مخطط syslog_json أعلاه)، فيمكن استخدام أمر الإدراج نفسه. ولكن يجب تحديد JSONAsObject بوصفه التنسيق بدلًا من JSONEachRow، على سبيل المثال:
elasticdump --input=${ELASTICSEARCH_URL} --type=data --input-index ${ELASTICSEARCH_INDEX} --output=$ --sourceOnly --searchAfter --pit=true | 
clickhouse-client --host ${CLICKHOUSE_HOST} --secure --password ${CLICKHOUSE_PASSWORD} --user ${CLICKHOUSE_USER} --max_insert_block_size=1000 \
--min_insert_block_size_bytes=0 --min_insert_block_size_rows=1000 --query="INSERT INTO test.logs_system_syslog FORMAT JSONAsObject"
راجع “Reading JSON as an object” لمزيد من التفاصيل.
5

تحويل البيانات (اختياري)

تفترض الأوامر أعلاه وجود مطابقة 1:1 بين حقول Elasticsearch وأعمدة ClickHouse. وغالبًا ما يحتاج المستخدمون إلى تصفية بيانات Elasticsearch وتحويلها قبل إدخالها إلى ClickHouse.يمكن تحقيق ذلك باستخدام table function ‏input، التي تتيح لنا تنفيذ أي استعلام SELECT على stdout.لنفترض أننا نريد تخزين حقلي timestamp وhostname فقط من بياناتنا السابقة. بنية ClickHouse:
CREATE TABLE logs_system_syslog_v2
(
    `timestamp` DateTime,
    `hostname` String
)
ENGINE = MergeTree
ORDER BY (hostname, timestamp)
لإدراج البيانات من elasticdump إلى هذا الجدول، يمكننا ببساطة استخدام دالة الجدول input، مع استخدام نوع JSON لاكتشاف الأعمدة المطلوبة وتحديدها ديناميكيًا. لاحظ أن استعلام SELECT هذا يمكن أن يتضمن شرط تصفية بسهولة.
elasticdump --input=${ELASTICSEARCH_URL} --type=data --input-index ${ELASTICSEARCH_INDEX} --output=$ --sourceOnly --searchAfter --pit=true |
clickhouse-client --host ${CLICKHOUSE_HOST} --secure --password ${CLICKHOUSE_PASSWORD} --user ${CLICKHOUSE_USER} --max_insert_block_size=1000 \
--min_insert_block_size_bytes=0 --min_insert_block_size_rows=1000 --query="INSERT INTO test.logs_system_syslog_v2 SELECT json.\`@timestamp\` as timestamp, json.host.hostname as hostname FROM input('json JSON') FORMAT JSONAsObject"
لاحظ ضرورة استخدام حرف الهروب مع اسم الحقل @timestamp واستخدام صيغة الإدخال JSONAsObject.
آخر تعديل في ٢٥ يونيو ٢٠٢٦