Cloud Bigtable لمستخدمي Cassandra

1. مقدمة

هذا الدرس التطبيقي حول الترميز هو دليل لأي شخص يُرحِّل طلبات بحث من Apache Cassandra إلى Google Cloud Bigtable.

في هذا الدرس التطبيقي حول الترميز،

  • استخدام محاكي Cloud Bigtable
  • استكشاف حالة استخدام السلاسل الزمنية
  • إنشاء مجموعة جدول وأعمدة
  • تعرّف على مكافئات Cloud Bigtable Java لـ CQL Insert, Update, Select, Delete

ما هو تقييمك لتجربتك في استخدام Google Cloud Platform؟

حديث متوسط بارع

كيف ستستخدم هذا البرنامج التعليمي؟

القراءة فقط اقرأها وأكمِل التمارين

2. إعداد

سوف تنظر إلى نموذج لمجموعة بيانات تحتوي على عدد قليل من الصفوف فقط للسماح لك بفهم المفاهيم الأساسية بسرعة.

كاساندرا

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

إذا كنت تتابع، فأنشئ مفتاحًا واستخدمه. لن تكون استراتيجية النسخ المماثل مهمة هنا.

cqlsh> create keyspace mykeyspace with replication = {'class':'SimpleStrategy','replication_factor' : 2};
cqlsh> use mykeyspace;

Cloud Bigtable

ستحتاج إلى مثيل Cloud Bigtable لجدولك. ويمكنك إعداد مثيل محلي مجانًا باستخدام المحاكي. لن تحتاج إلى إنشاء مساحة مفاتيح في Cloud Bigtable، حيث يتم التعامل مع النسخ المتماثل من خلال إعداد المثيل الخاص بك.

استخدم الأمر التالي لبدء المحاكي:

gcloud beta emulators bigtable start

ثم في نافذة أوامر أو علامة تبويب أخرى، اضبط متغير بيئة المحاكي باستخدام الأمر التالي:

$(gcloud beta emulators bigtable env-init) #Sets BIGTAB`LE_EMULATOR_HOST

أنشئ بعد ذلك مشروعًا Java ستستخدمه لتشغيل أمثلة التعليمات البرمجية، واستورد عميل Cloud Bigtable باستخدام Maven أو Gradle أو SBT. ثم في ملف Java جديد، أنشئ اتصالاً بعميل البيانات.

BigtableDataSettings settings =
    BigtableDataSettings.newBuilder().setProjectId(projectId).setInstanceId(instanceId).build();

try {
  dataClient = BigtableDataClient.create(settings);
} catch (Exception e) {
  System.out.println("Error during data client connection: \n" + e.toString());
}

3- إنشاء جداول

في كل من جدولي Cassandra وCloud Bigtable، يحتوي كل صف على مفتاح مرتبط به. تتضمن مفاتيح Cassandra مفتاح تقسيم وعمود تجميع يمكن أن يكون منفصلاً أو متداخلاً. تُستخدم مفاتيح Cloud Bigtable بأكملها للتقسيمات (الأقسام) والترتيب. هذان النظامان متشابهان بشكل لا يصدق عندما يتعلق الأمر بإنشاء المفتاح الأساسي/الصف. كلا النظامين عبارة عن قوائم مرتبة قاموسًا بشكل أساسي حيث تعمل المفاتيح كشكل رئيسي لتوزيع الصف بين النقاط. في معظم الحالات، يمكنك إعادة استخدام المفتاح نفسه في Cloud Bigtable.

في هذا الدرس التطبيقي، ستستخدم Cloud Bigtable لتخزين بيانات السلاسل الزمنية المتعلقة بالهواتف الجوّالة والأجهزة اللوحية الجوّالة (يجب عدم الخلط بينها وبين الأجهزة اللوحية الكبيرة الحجم). فيما يلي إرشادات إنشاء الجدول.

كاساندرا

cqlsh:mykeyspace> create table mobileTimeSeries (
           deviceid text,
           devicetype text,
           date date,
           connected_cell map<timestamp,Boolean>, 
           os_build text, 
           os_name text,
           PRIMARY KEY((devicetype, deviceid), date));

Cloud Bigtable

يمكنك إنشاء مجموعة جداول وأعمدة باستخدام عميل Java، ولكن من الأسهل استخدام الأمر التالي مع أداة cbt:

cbt createtable mobile-time-series families=stats_summary

Cloud Bigtable هي قاعدة بيانات NoSQL، لذلك لن تحتاج إلى تعريف مخطط عند إنشاء الجدول، ولكنك سترغب في التفكير في الاستعلامات التي ستقوم بتشغيلها وتحسين مفتاح الصف لها.

تتمثل الاستراتيجية الأكثر شيوعًا لنقل المفاتيح في استخدام جميع مفاتيح التقسيم وأعمدة التجميع ودمجها لإنشاء سلسلة تمثِّل مفتاح صف Cloud Bigtable. ننصح بشكل عام باستخدام مفاتيح مستندة إلى السلسلة، لأنّها تساعد في تصحيح أخطاء توزيع المفاتيح من خلال Key Visualizer. يمكنك استخدام فاصل مثل التجزئة "#" بين قيم العمود للمساعدة في سهولة القراءة.

في هذا المثال، سنستخدم مفتاح صف "[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]"

4. الإدخالات

الإدخالات متشابهة إلى حد ما بين Cassandra وCloud Bigtable. ستُدرج هنا صفًا واحدًا ثم عدة صفوف باستخدام مفتاح الصف "[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]".

كاساندرا

أغنية منفردة

cqlsh:mykeyspace> insert into mobileTimeSeries (deviceid, devicetype, date, connected_cell, os_build) values ('4c410523', 'phone',toDate(now()), {toTimeStamp(now()): true}, 'PQ2A.190405.003');

الدُفعة

cqlsh:mykeyspace> BEGIN BATCH
insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-01', 'chromeos', '12155.0.0-rc1');
insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-02','chromeos', '12145.0.0-rc6');
APPLY BATCH;

Cloud Bigtable

أغنية منفردة

أنشِئ عملية تغيير باستخدام مفتاح الصف والبيانات التي تريد استخدامها، ثم طبِّق التغيير مع عميل البيانات. ستضيف صفًا من البيانات للهاتف يحتوي على معلومات حول اتصال الخلية ونظام التشغيل الخاص به.

try {
  System.currentTimeMillis();
  long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00

  String rowKey = "phone#4c410523#20190501";
  ByteString one = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 1});

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(
              COLUMN_FAMILY_NAME,
              ByteString.copyFrom("connected_cell".getBytes()),
              timestamp,
              one)
          .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "PQ2A.190405.003");

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during Write: \n" + e.toString());
}

الدُفعة

حدِّد تغيُّرات متعدّدة في عنصرBulkMutation، ثم استخدِم برنامج البيانات لتطبيق جميع التغييرات من خلال طلب بيانات واحد من واجهة برمجة التطبيقات. ستضيف بضعة أيام من البيانات حول اسم وإصدار نظام تشغيل الجهاز اللوحي.

try {
  long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00

  BulkMutation bulkMutation =
      BulkMutation.create(tableId)
          .add(
              "tablet#a0b81f74#20190501",
              Mutation.create()
                  .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
                  .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc1"))
          .add(
              "tablet#a0b81f74#20190502",
              Mutation.create()
                  .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
                  .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc6"));

  dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
  System.out.println("Error during WriteBatch: \n" + e.toString());
}

5- التحديثات

هنا ستقوم بتحديث خلية لم تتم كتابتها بعد ثم كتابة قيمة جديدة إلى خلية مع الاحتفاظ بالنُسخ السابقة أيضًا.

كاساندرا

إضافة خلايا

cqlsh:mykeyspace> UPDATE mobileTimeSeries SET os_name = 'android' WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';

تعديل الخلايا

cqlsh:mykeyspace> UPDATE mobileTimeSeries SET connected_cell = connected_cell +  {toTimeStamp(now()): false} WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';

Cloud Bigtable

في Cloud Bigtable، يمكنك التعامل مع التحديثات بالطريقة نفسها التي تتعامل بها مع عمليات الكتابة.

إضافة خلايا

يشبه ذلك كتابة الخلايا، فما عليك سوى تقديم عمود لم تكتب إليه من قبل. عليك هنا إضافة اسم نظام التشغيل إلى صف الهاتف.

try {
  long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30

  String rowKey = "phone#4c410523#20190501";

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "android");

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during update: \n" + e.toString());
}

جارٍ تحديث الخلايا

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

try {
  long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30

  String rowKey = "phone#4c410523#20190501";

  ByteString zero = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 0});

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(
              COLUMN_FAMILY_NAME,
              ByteString.copyFrom("connected_cell".getBytes()),
              timestamp,
              zero);

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during update2: \n" + e.toString());
}

6- اختيار

الآن، ستقوم باسترداد البيانات التي كتبتها في الجدول. عند ترحيل عبارات تحديد CQL، تحتاج إلى مراعاة العديد من جوانب عبارات التحديد مثل الأعمدة، والتصفية عبر عبارات المكان، والحد من الدوال وتجميعها مثل "التجميع حسب". هنا، عليك فقط إلقاء نظرة على عبارتين بسيطتين محددتين للحصول على الفكرة الأساسية، ولكن يمكنك إلقاء نظرة في الوثائق للحصول على مزيد من المعلومات حول الاختيار. في Cloud Bigtable، هناك نوعان من عمليات الاسترداد: التلقي والفحص. تسترد القيمة صفًا واحدًا بينما يسترد الفحص نطاق الصفوف.

كاساندرا

أغنية منفردة

cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-04';

عدة بلدان

cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='tablet' AND deviceid = 'a0b81f74' AND date >= '2019-09-04';

Cloud Bigtable

أعزب

يمكنك استخدام البحث في الصفوف للحصول على بيانات لهاتف معيّن في التاريخ المحدّد ضمن صف واحد. سيؤدي ذلك إلى عرض كل نسخة ذات طابع زمني من القيم، لذا من المفترض أن يظهر سطران لـ Connect_cell في طوابع زمنية مختلفة.

try {
  String rowKey = "phone#4c410523#20190501";

  Row row = dataClient.readRow(tableId, rowKey);
  for (RowCell cell : row.getCells()) {

    System.out.printf(
        "Family: %s    Qualifier: %s    Value: %s    Timestamp: %s%n",
        cell.getFamily(),
        cell.getQualifier().toStringUtf8(),
        cell.getValue().toStringUtf8(),
        cell.getTimestamp());
  }
} catch (Exception e) {
  System.out.println("Error during lookup: \n" + e.toString());
}

بلدان متعددة

استخدام فحص نطاق لعرض بيانات شهر لجهاز محمول محدد منتشرة على صفوف متعددة. ويمكنك استخدام فلتر مع هذه الفلاتر للحصول على نُسخ معيّنة فقط من البيانات أو الفلترة حسب القيم.

try {
  Query query = Query.create(tableId).range("tablet#a0b81f74#201905", "tablet#a0b81f74#201906");
  ServerStream<Row> rowStream = dataClient.readRows(query);
  for (Row row : rowStream) {
    System.out.println("Row Key: " + row.getKey().toStringUtf8());
    for (RowCell cell : row.getCells()) {

      System.out.printf(
          "Family: %s    Qualifier: %s    Value: %s    Timestamp: %s%n",
          cell.getFamily(),
          cell.getQualifier().toStringUtf8(),
          cell.getValue().toStringUtf8(),
          cell.getTimestamp());
    }
  }
} catch (Exception e) {
  System.out.println("Error during scan: \n" + e.toString());
}

7. للحذف

ستحذف هنا البيانات التي تضعها في جدولك. ستحذف أولاً صفًا فرديًا، ثم ستحذف عدة صفوف.

يتيح CQL من Cassandra عمليات حذف صف واحد وكذلك عمليات إزالة النطاق عند تحديد جميع الأعمدة الأساسية. يمكنك القيام بذلك باستخدام Bigtable من خلال فحص نطاق ثم إجراء عمليات الحذف على مستوى الصف. لاحظ أنك ستحصل على النتيجة نفسها، ولكن سيكون لديك المزيد من العمليات لأن كل عملية حذف سيتم تشغيلها على حدة.

كاساندرا

أغنية منفردة

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='phone' and deviceid = '4c410523';

عدة بلدان

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='tablet' and deviceid = 'a0b81f74';

Cloud Bigtable

أغنية منفردة

سيتم هنا حذف البيانات الخاصة بهاتف وتاريخ محدّدَين. استخدِم مفتاح الصف لحذف صف واحد في كل مرة.

try {
  String rowKey = "phone#4c410523#20190501";

  RowMutation mutation = RowMutation.create(tableId, rowKey).deleteRow();

  dataClient.mutateRow(mutation);
} catch (Exception e) {
  System.out.println("Error during Delete: \n" + e.toString());
}

عدة بلدان

ستحذف هنا جميع البيانات لجهاز لوحي محدد. لنقل استعلام CQL-استعلام وحذف صفوف متعددة، قد تحتاج إلى إجراء فحص ثم حذف كل صف باستخدام المجموعة الناتجة من مفاتيح الصفوف.

try {
  Query query = Query.create(tableId).prefix("tablet#a0b81f7");
  ServerStream<Row> rowStream = dataClient.readRows(query);
  BulkMutation bulkMutation = BulkMutation.create(tableId);
  for (Row row : rowStream) {
    bulkMutation.add(row.getKey(), Mutation.create().deleteRow());
  }

  dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
  System.out.println("Error during DeleteMultiple: \n" + e.toString());
}

8. على وشك الانتهاء

إخلاء مساحة

كاساندرا

إذا قمت بإنشاء مجموعة Cassandra لمتابعة هذا، فلا تتردد في حذفها كما تفعل عادةً.

Cloud Bigtable

إذا أنشأت الجدول على مثيل Cloud Bigtable حالي، يمكنك حذفه باستخدام الأمر cbt

cbt deletetable mobile-time-series

وإذا استخدمت المحاكي، فيمكنك إيقاف تشغيله بالكامل، وذلك من خلال كتابة مفتاح CTRL-C في الطرف الذي بدأته فيه.

الخطوات التالية