الانتقال إلى المحتوى الرئيسي
يفيد توليد البيانات العشوائية عند اختبار حالات استخدام جديدة أو إجراء اختبارات قياس الأداء لتطبيقك. يوفّر ClickHouse مجموعة واسعة من الدوال لتوليد البيانات العشوائية تُغني، في كثير من الحالات، عن الحاجة إلى مولّد بيانات خارجي. يقدّم هذا الدليل عدة أمثلة على كيفية توليد مجموعات بيانات عشوائية في ClickHouse بمتطلبات متفاوتة للعشوائية.

مجموعة بيانات بسيطة بتوزيع منتظم

حالة الاستخدام: أنشئ بسرعة مجموعة بيانات لأحداث المستخدمين بطوابع زمنية عشوائية وأنواع أحداث عشوائية.
CREATE TABLE user_events (
  event_id UUID,
  user_id UInt32,
  event_type LowCardinality(String),
  event_time DateTime
) ENGINE = MergeTree
ORDER BY event_time;

INSERT INTO user_events
SELECT
  generateUUIDv4() AS event_id,
  rand() % 10000 AS user_id,
  arrayElement(['click','view','purchase'], toUInt32(rand()) % 3 + 1) AS event_type,
  now() - INTERVAL rand() % 3600*24 SECOND AS event_time
FROM numbers(1000000);
  • rand() % 10000: توزيع منتظم لـ 10 آلاف مستخدم
  • arrayElement(...): يختار عشوائيًا نوعًا واحدًا من ثلاثة أنواع أحداث
  • الطوابع الزمنية موزعة على مدى الساعات الأربع والعشرين الماضية

التوزيع الأُسّي

حالة الاستخدام: محاكاة مبالغ المشتريات، بحيث تكون معظم القيم منخفضة، بينما تكون قلة منها مرتفعة.
CREATE TABLE purchases (
  dt DateTime,
  customer_id UInt32,
  total_spent Float32
) ENGINE = MergeTree
ORDER BY dt;

INSERT INTO purchases
SELECT
  now() - INTERVAL randUniform(1,1_000_000) SECOND AS dt,
  number AS customer_id,
  15 + round(randExponential(1/10), 2) AS total_spent
FROM numbers(500000);
  • طوابع زمنية موزعة بانتظام خلال فترة حديثة
  • randExponential(1/10) — معظم القيم قريبة من 0، مع إزاحة قدرها 15 كحد أدنى ([ClickHouse][1], [ClickHouse][2], [Atlantic.Net][3], [GitHub][4])

الأحداث الموزعة زمنيًا (Poisson)

حالة الاستخدام: محاكاة وصول الأحداث بحيث تتكتل حول فترة زمنية محددة (مثل ساعة الذروة).
CREATE TABLE events (
  dt DateTime,
  event_type String
) ENGINE = MergeTree
ORDER BY dt;

INSERT INTO events
SELECT
  toDateTime('2022-12-12 12:00:00')
    - ((12 + randPoisson(12)) * 3600) AS dt,
  'click' AS event_type
FROM numbers(200000);
  • تبلغ الأحداث ذروتها قرابة الظهر، مع انحراف يتبع توزيع بواسون

التوزيع الطبيعي المتغيّر بمرور الوقت

حالة الاستخدام: محاكاة مقاييس النظام (مثل استخدام CPU) التي تتغيّر بمرور الوقت.
CREATE TABLE IF NOT EXISTS cpu_metrics (
    host String,
    ts   DateTime,
    usage Float32
) ENGINE = MergeTree
ORDER BY (host, ts);

INSERT INTO cpu_metrics
SELECT
    arrayJoin(['host1','host2','host3']) AS host,
    now() - INTERVAL number SECOND AS ts,
    greatest(0.0, least(100.0,
        (50 + 30 * sin(toUInt32(number) % 86400 / 86400.0 * 2 * pi()))
        + randNormal(0, 10)
    )) AS usage
FROM numbers(10000);
  • يتبع usage موجة جيبية يومية + بعض العشوائية
  • القيم محصورة بين [0,100]

البيانات الفئوية وبيانات Nested

حالة الاستخدام: أنشئ ملفات تعريف للمستخدمين تتضمن اهتمامات متعددة القيم.
CREATE TABLE user_profiles (
  user_id UInt32,
  interests Array(String),
  scores Array(UInt8)
) ENGINE = MergeTree
ORDER BY user_id;

INSERT INTO user_profiles
SELECT
  number AS user_id,
  arrayShuffle(['sports','music','tech'])[1 + rand() % 3 : 1 + rand() % 3] AS interests,
  [rand() % 100, rand() % 100, rand() % 100] AS scores
FROM numbers(20000);
  • طول عشوائي للمصفوفة بين 1 و3
  • ثلاث درجات لكل مستخدم في كل اهتمام
اقرأ مدونة Generating Random Data in ClickHouse للاطلاع على المزيد من الأمثلة.

إنشاء جداول عشوائية

تُعد الدالة generateRandomStructure مفيدة للغاية عند استخدامها مع محرك الجدول generateRandom لأغراض الاختبار، وقياس الأداء، أو إنشاء بيانات وهمية بمخططات عشوائية. لنبدأ أولًا بإلقاء نظرة على شكل البنية العشوائية باستخدام الدالة generateRandomStructure:
SELECT generateRandomStructure(5);
قد ترى شيئًا كهذا:
c1 UInt32, c2 Array(String), c3 DateTime, c4 Nullable(Float64), c5 Map(String, Int16)
يمكنك أيضًا استخدام seed للحصول على البنية نفسها في كل مرة:
SELECT generateRandomStructure(3, 42);
c1 String, c2 Array(Nullable(Int32)), c3 Tuple(UInt8, Date)
لننشئ الآن جدولًا حقيقيًا ونملأه ببيانات عشوائية:
CREATE TABLE my_test_table
ENGINE = MergeTree
ORDER BY tuple()
AS SELECT * 
FROM generateRandom(
    'col1 UInt32, col2 String, col3 Float64, col4 DateTime',
    1,  -- seed for data generation
    10  -- number of different random values
)
LIMIT 100;  -- 100 rows

-- Step 2: Query your new table
SELECT * FROM my_test_table LIMIT 5;
┌───────col1─┬─col2──────┬─────────────────────col3─┬────────────────col4─┐
│ 4107652264 │ &b!M-e;7  │  1.0013455832230728e-158 │ 2059-08-14 19:03:26 │
│  652895061 │ Dj7peUH{T │   -1.032074207667996e112 │ 2079-10-06 04:18:16 │
│ 2319105779 │ =D[       │    -2.066555415720528e88 │ 2015-04-26 11:44:13 │
│ 1835960063 │ _@}a      │  -1.4998020545039013e110 │ 2063-03-03 20:36:55 │
│  730412674 │ _}!       │ -1.3578492992094465e-275 │ 2098-08-23 18:23:37 │
└────────────┴───────────┴──────────────────────────┴─────────────────────┘
لنَدمج كلتا الدالتين للحصول على table عشوائي تمامًا. أولًا، لنرَ البنية التي سنحصل عليها:
SELECT generateRandomStructure(7, 123) AS structure FORMAT vertical;
┌─structure──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ c1 Decimal64(7), c2 Enum16('c2V0' = -21744, 'c2V1' = 5380), c3 Int8, c4 UUID, c5 UUID, c6 FixedString(190), c7 Map(Enum16('c7V0' = -19581, 'c7V1' = -10024, 'c7V2' = 27615, 'c7V3' = -10177, 'c7V4' = -19644, 'c7V5' = 3554, 'c7V6' = 29073, 'c7V7' = 28800, 'c7V8' = -11512), Float64) │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
الآن أنشئ الجدول وفق هذا الهيكل، ثم استخدم تعليمة DESCRIBE لمعرفة ما أنشأناه:
CREATE TABLE fully_random_table
ENGINE = MergeTree
ORDER BY tuple()
AS SELECT * 
FROM generateRandom(generateRandomStructure(7, 123), 1, 10)
LIMIT 1000;

DESCRIBE TABLE fully_random_table;
   ┌─name─┬─type─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
1. │ c1   │ Decimal(18, 7)                                                                                                                                                           │              │                    │         │                  │                │
2. │ c2   │ Enum16('c2V0' = -21744, 'c2V1' = 5380)                                                                                                                                   │              │                    │         │                  │                │
3. │ c3   │ Int8                                                                                                                                                                     │              │                    │         │                  │                │
4. │ c4   │ UUID                                                                                                                                                                     │              │                    │         │                  │                │
5. │ c5   │ UUID                                                                                                                                                                     │              │                    │         │                  │                │
6. │ c6   │ FixedString(190)                                                                                                                                                         │              │                    │         │                  │                │
7. │ c7   │ Map(Enum16('c7V4' = -19644, 'c7V0' = -19581, 'c7V8' = -11512, 'c7V3' = -10177, 'c7V1' = -10024, 'c7V5' = 3554, 'c7V2' = 27615, 'c7V7' = 28800, 'c7V6' = 29073), Float64) │              │                    │         │                  │                │
   └──────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
افحص الصف الأول للاطّلاع على عيّنة من البيانات المُولَّدة:
SELECT * FROM fully_random_table LIMIT 1 FORMAT vertical;
Row 1:
──────
c1: 80416293882.257732 -- 80.42 billion
c2: c2V1
c3: -84
c4: 1a9429b3-fd8b-1d72-502f-c051aeb7018e
c5: 7407421a-031f-eb3b-8571-44ff279ddd36
c6: g̅b�&��rҵ���5C�\�|��H�>���l'V3��R�[��=3�G�LwVMR*s緾/2�J.���6#��(�h>�lە��L^�M�:�R�9%d�ž�zv��W����Y�S��_no��BP+��u��.0��UZ!x�@7:�nj%3�Λd�S�k>���w��|�&��~
c7: {'c7V8':-1.160941256852442}
آخر تعديل في ٢٩ يونيو ٢٠٢٦