1. مقدمة
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية استخدام Cloud Bigtable مع برنامج Java HBase.
ستتعرّف على كيفية
- تجنُّب الأخطاء الشائعة في تصميم المخطط
- استيراد البيانات في ملف تسلسلي
- الاستعلام عن بياناتك
عند الانتهاء، ستتوفّر لديك عدة خرائط تعرض بيانات حافلات مدينة نيويورك. على سبيل المثال، ستنشئ خريطة التمثيل اللوني هذه لرحلات الحافلات في مانهاتن:

ما هو تقييمك لتجربة استخدام Google Cloud Platform؟
كيف ستستخدم هذا البرنامج التعليمي؟
2. لمحة عن مجموعة البيانات
ستطّلع على مجموعة بيانات حول حافلات مدينة نيويورك. تتوفّر أكثر من 300 حافلة و5,800 مركبة تسير على هذه المسارات. مجموعة البيانات هي سجلّ يتضمّن اسم الوجهة ومعرّف المركبة وخطوط الطول والعرض ووقت الوصول المتوقّع ووقت الوصول المُجدوَل. تتألف مجموعة البيانات من لقطات تم التقاطها كل 10 دقائق تقريبًا خلال شهر يونيو 2017.
3- تصميم المخطط
للحصول على أفضل أداء من Cloud Bigtable، عليك التفكير مليًا عند تصميم المخطط. يتم فرز البيانات في Cloud Bigtable تلقائيًا حسب الترتيب المعجمي، لذا إذا صمّمت المخطط بشكل جيد، سيكون طلب البحث عن البيانات ذات الصلة فعّالاً للغاية. تتيح Cloud Bigtable تنفيذ طلبات بحث باستخدام عمليات بحث نقطية حسب مفتاح الصف أو عمليات فحص لنطاق الصفوف التي تعرض مجموعة متجاورة من الصفوف. ومع ذلك، إذا لم يتم التفكير جيدًا في المخطط، قد تجد نفسك تجمع عمليات بحث متعددة عن الصفوف، أو الأسوأ من ذلك، إجراء عمليات بحث كاملة في الجدول، وهي عمليات بطيئة للغاية.
التخطيط لطلبات البحث
تتضمّن بياناتنا مجموعة متنوعة من المعلومات، ولكن في هذا الدرس التطبيقي حول الترميز، ستستخدم الموقع الجغرافي والوجهة للحافلة.
باستخدام هذه المعلومات، يمكنك تنفيذ طلبات البحث التالية:
- الحصول على الموقع الجغرافي لحافلة واحدة خلال ساعة معيّنة
- الحصول على بيانات يوم كامل لخط حافلات أو حافلة معيّنة
- العثور على جميع الحافلات في مستطيل على الخريطة
- الحصول على المواقع الجغرافية الحالية لجميع الحافلات (في حال كنت تستورد هذه البيانات في الوقت الفعلي)
لا يمكن تنفيذ مجموعة طلبات البحث هذه معًا على النحو الأمثل. على سبيل المثال، إذا كنت تريد ترتيب البيانات حسب الوقت، لا يمكنك إجراء عملية مسح ضوئي استنادًا إلى موقع جغرافي بدون إجراء مسح ضوئي للجدول بأكمله. عليك تحديد الأولويات استنادًا إلى طلبات البحث التي تُجريها عادةً.
في هذا الدرس التطبيقي، ستركز على تحسين وتنفيذ مجموعة الاستعلامات التالية:
- الحصول على المواقع الجغرافية لمركبة معيّنة على مدار ساعة
- الحصول على المواقع الجغرافية لخط حافلات كامل على مدار ساعة
- الحصول على المواقع الجغرافية لجميع الحافلات في مانهاتن خلال ساعة
- احصل على أحدث المواقع الجغرافية لجميع الحافلات في مانهاتن خلال ساعة واحدة.
- الحصول على المواقع الجغرافية لخط حافلات كامل على مدار الشهر
- الحصول على المواقع الجغرافية لخط حافلات كامل يتّجه إلى وجهة معيّنة خلال ساعة
تصميم مفتاح الصف
في هذا الدرس التطبيقي، ستعمل على مجموعة بيانات ثابتة، ولكنك ستصمّم مخططًا قابلًا للتوسّع. ستصمّم مخططًا يتيح لك بث المزيد من بيانات الحافلات إلى الجدول مع الحفاظ على الأداء الجيّد.
في ما يلي المخطط المقترَح لمفتاح الصف:
[شركة الحافلات/خط الحافلات/الطابع الزمني مقربًا إلى أقرب ساعة/معرّف المركبة]. يحتوي كل صف على ساعة من البيانات، وتحتوي كل خلية على إصدارات متعددة من البيانات تحمل طابعًا زمنيًا.
في هذا الدرس التطبيقي، ستستخدم مجموعة أعمدة واحدة لتبسيط الأمور. في ما يلي مثال على شكل البيانات. يتم ترتيب البيانات حسب مفتاح الصف.
مفتاح الصف | cf:VehicleLocation.Latitude | cf:VehicleLocation.Longitude | ... |
MTA/M86-SBS/1496275200000/NYCT_5824 | 40.781212 @20:52:54.0040.776163 @20:43:19.0040.778714 @20:33:46.00 | -73.961942 @20:52:54.00-73.946949 @20:43:19.00-73.953731 @20:33:46.00 | ... |
MTA/M86-SBS/1496275200000/NYCT_5840 | 40.780664 @20:13:51.0040.788416 @20:03:40.00 | -73.958357 @20:13:51.00 -73.976748 @20:03:40.00 | ... |
MTA/M86-SBS/1496275200000/NYCT_5867 | 40.780281 @20:51:45.0040.779961 @20:43:15.0040.788416 @20:33:44.00 | -73.946890 @20:51:45.00-73.959465 @20:43:15.00-73.976748 @20:33:44.00 | ... |
... | ... | ... | ... |
4. إنشاء مثيل وجدول ومجموعة أعمدة
بعد ذلك، ستنشئ جدول Cloud Bigtable.
أولاً، أنشئ مشروعًا جديدًا. استخدِم Cloud Shell المضمّن، والذي يمكنك فتحه من خلال النقر على الزر "تفعيل Cloud Shell" في أعلى يسار الصفحة.

اضبط متغيرات البيئة التالية لتسهيل عملية نسخ أوامر codelab ولصقها:
INSTANCE_ID="bus-instance" CLUSTER_ID="bus-cluster" TABLE_ID="bus-data" CLUSTER_NUM_NODES=3 CLUSTER_ZONE="us-central1-c"
تتضمّن Cloud Shell الأدوات التي ستستخدمها في هذا الدرس العملي، وهي أداة سطر الأوامر gcloud وواجهة سطر الأوامر cbt وMaven، وكلها مثبّتة مسبقًا.
فعِّل واجهات برمجة التطبيقات Cloud Bigtable API من خلال تنفيذ هذا الأمر.
gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com
أنشئ مثيلاً من خلال تنفيذ الأمر التالي:
gcloud bigtable instances create $INSTANCE_ID \
--cluster=$CLUSTER_ID \
--cluster-zone=$CLUSTER_ZONE \
--cluster-num-nodes=$CLUSTER_NUM_NODES \
--display-name=$INSTANCE_ID
بعد إنشاء المثيل، املأ ملف إعدادات CBT، ثم أنشئ جدولاً ومجموعة أعمدة من خلال تنفيذ الأوامر التالية:
echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf
5- استيراد البيانات
استيراد مجموعة من ملفات التسلسل لهذا الدرس التطبيقي من gs://cloud-bigtable-public-datasets/bus-data باتّباع الخطوات التالية:
فعِّل Cloud Dataflow API من خلال تنفيذ هذا الأمر.
gcloud services enable dataflow.googleapis.com
نفِّذ الأوامر التالية لاستيراد الجدول.
NUM_WORKERS=$(expr 3 \* $CLUSTER_NUM_NODES) gcloud beta dataflow jobs run import-bus-data-$(date +%s) \ --gcs-location gs://dataflow-templates/latest/GCS_SequenceFile_to_Cloud_Bigtable \ --num-workers=$NUM_WORKERS --max-workers=$NUM_WORKERS \ --parameters bigtableProject=$GOOGLE_CLOUD_PROJECT,bigtableInstanceId=$INSTANCE_ID,bigtableTableId=$TABLE_ID,sourcePattern=gs://cloud-bigtable-public-datasets/bus-data/*
مراقبة عملية الاستيراد
يمكنك مراقبة المهمة في واجهة مستخدم Cloud Dataflow. يمكنك أيضًا الاطّلاع على الحمل على مثيل Cloud Bigtable باستخدام واجهة مستخدم المراقبة. من المفترض أن تستغرق عملية الاستيراد بأكملها 5 دقائق.
6. الحصول على الشفرة
git clone https://github.com/googlecodelabs/cbt-intro-java.git cd cbt-intro-java
غيِّر إلى Java 11 من خلال تنفيذ الأوامر التالية:
sudo update-java-alternatives -s java-1.11.0-openjdk-amd64 && export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
7. إجراء عملية بحث
الاستعلام الأول الذي ستنفّذه هو بحث بسيط عن صف. ستحصل على بيانات الحافلة على خط M86-SBS في 1 يونيو 2017 من الساعة 12:00 صباحًا إلى الساعة 1:00 صباحًا. وتكون مركبة تحمل المعرّف NYCT_5824 على خط الحافلة في ذلك الوقت.
باستخدام هذه المعلومات ومعرفة تصميم المخطط (شركة الحافلات/خط الحافلات/الطابع الزمني الذي تم تقريبه إلى أقرب ساعة/رقم تعريف المركبة)، يمكنك استنتاج أنّ مفتاح الصف هو:
MTA/M86-SBS/1496275200000/NYCT_5824
BusQueries.java
private static final byte[] COLUMN_FAMILY_NAME = Bytes.toBytes("cf");
private static final byte[] LAT_COLUMN_NAME = Bytes.toBytes("VehicleLocation.Latitude");
private static final byte[] LONG_COLUMN_NAME = Bytes.toBytes("VehicleLocation.Longitude");
String rowKey = "MTA/M86-SBS/1496275200000/NYCT_5824";
Result getResult =
table.get(
new Get(Bytes.toBytes(rowKey))
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME));
يجب أن تتضمّن النتيجة أحدث موقع جغرافي للحافلة خلال تلك الساعة. ولكنك تريد الاطّلاع على جميع المواقع الجغرافية، لذا اضبط الحد الأقصى لعدد الإصدارات في طلب GET.
BusQueries.java
Result getResult =
table.get(
new Get(Bytes.toBytes(rowKey))
.setMaxVersions(Integer.MAX_VALUE)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME));
في Cloud Shell، شغِّل الأمر التالي للحصول على قائمة بخطوط الطول والعرض للحافلة خلال الساعة:
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=lookupVehicleInGivenHour
يمكنك نسخ خطوط الطول والعرض ولصقها في تطبيق MapMaker لعرض النتائج. بعد بضع طبقات، سيُطلب منك إنشاء حساب مجاني. يمكنك إنشاء حساب أو حذف الطبقات الحالية فقط. يتضمّن هذا الدرس التطبيقي حول الترميز نموذجًا مرئيًا لكل خطوة، إذا كنت تريد فقط اتّباع التعليمات. إليك نتيجة طلب البحث الأول:

8. إجراء فحص
الآن، لنعرض جميع البيانات الخاصة بخط الحافلات لهذا الوقت. يبدو رمز المسح الضوئي مشابهًا إلى حدّ كبير لرمز الحصول على الرمز. تمنح الماسح الضوئي موضعًا للبدء ثم تشير إلى أنّك تريد فقط صفوفًا لخط الحافلات M86-SBS خلال الساعة المحدّدة بالطابع الزمني 1496275200000.
BusQueries.java
Scan scan;
scan = new Scan();
scan.setMaxVersions(Integer.MAX_VALUE)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME)
.withStartRow(Bytes.toBytes("MTA/M86-SBS/1496275200000"))
.setRowPrefixFilter(Bytes.toBytes("MTA/M86-SBS/1496275200000"));
ResultScanner scanner = table.getScanner(scan);
نفِّذ الأمر التالي للحصول على النتائج.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanBusLineInGivenHour

يمكن لتطبيق "صانع الخرائط" عرض قوائم متعددة في الوقت نفسه، ما يتيح لك معرفة الحافلات التي تمثّل المركبة من طلب البحث الأول الذي أجريته.

من التعديلات المثيرة للاهتمام على طلب البحث هذا عرض بيانات الشهر بأكمله لخط الحافلات M86-SBS، وهذا أمر سهل للغاية. ما عليك سوى إزالة الطابع الزمني من صف البدء وفلتر البادئة للحصول على النتيجة.
BusQueries.java
scan.withStartRow(Bytes.toBytes("MTA/M86-SBS/"))
.setRowPrefixFilter(Bytes.toBytes("MTA/M86-SBS/"));
// Optionally, reduce the results to receive one version per column
// since there are so many data points.
scan.setMaxVersions(1);
نفِّذ الأمر التالي للحصول على النتائج. (ستظهر قائمة طويلة من النتائج).
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanEntireBusLine
إذا نسخت النتائج إلى MapMaker، يمكنك الاطّلاع على خريطة التمثيل اللوني لمسار الحافلة. تشير النقاط البرتقالية إلى محطات التوقف، وتشير النقاط الحمراء الساطعة إلى بداية المسار ونهايته.

9- تقديم الفلاتر
بعد ذلك، ستُجري فلترة للحافلات المتجهة شرقًا والحافلات المتجهة غربًا، وستنشئ خريطة حرارية منفصلة لكل منهما.
BusQueries.java
Scan scan;
ResultScanner scanner;
scan = new Scan();
SingleColumnValueFilter valueFilter =
new SingleColumnValueFilter(
COLUMN_FAMILY_NAME,
Bytes.toBytes("DestinationName"),
CompareOp.EQUAL,
Bytes.toBytes("Select Bus Service Yorkville East End AV"));
scan.setMaxVersions(1)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME);
scan.withStartRow(Bytes.toBytes("MTA/M86-SBS/"))
.setRowPrefixFilter(Bytes.toBytes("MTA/M86-SBS/"));
scan.setFilter(valueFilter);
scanner = table.getScanner(scan);
نفِّذ الأمر التالي للحصول على نتائج الحافلات المتّجهة شرقًا.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingEast
للحصول على الحافلات المتّجهة غربًا، غيِّر السلسلة في valueFilter:
BusQueries.java
SingleColumnValueFilter valueFilter =
new SingleColumnValueFilter(
COLUMN_FAMILY_NAME,
Bytes.toBytes("DestinationName"),
CompareOp.EQUAL,
Bytes.toBytes("Select Bus Service Westside West End AV"));
نفِّذ الأمر التالي للحصول على نتائج الحافلات المتّجهة غربًا.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingWest
الحافلات المتّجهة إلى الشرق

الحافلات المتّجهة إلى الغرب

من خلال مقارنة الخريطتين الحراريتين، يمكنك الاطّلاع على الاختلافات في المسارات بالإضافة إلى ملاحظة الاختلافات في السرعة. أحد تفسيرات البيانات هو أنّ الحافلات التي تتّجه غربًا يتم إيقافها أكثر، خاصةً عند دخولها إلى "سنترال بارك". وفي الحافلات المتجهة شرقًا، لا نرى الكثير من نقاط الاختناق.
10. إجراء عملية فحص متعددة النطاقات
بالنسبة إلى طلب البحث الأخير، ستتعامل مع الحالة التي تهمّك فيها العديد من خطوط الحافلات في منطقة معيّنة:
BusQueries.java
private static final String[] MANHATTAN_BUS_LINES = {"M1","M2","M3",...
Scan scan;
ResultScanner scanner;
List<RowRange> ranges = new ArrayList<>();
for (String busLine : MANHATTAN_BUS_LINES) {
ranges.add(
new RowRange(
Bytes.toBytes("MTA/" + busLine + "/1496275200000"), true,
Bytes.toBytes("MTA/" + busLine + "/1496275200001"), false));
}
Filter filter = new MultiRowRangeFilter(ranges);
scan = new Scan();
scan.setFilter(filter);
scan.setMaxVersions(Integer.MAX_VALUE)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME);
scan.withStartRow(Bytes.toBytes("MTA/M")).setRowPrefixFilter(Bytes.toBytes("MTA/M"));
scanner = table.getScanner(scan);
نفِّذ الأمر التالي للحصول على النتائج.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanManhattanBusesInGivenHour

11. إنهاء
إخلاء مساحة لتجنُّب الرسوم
لتجنُّب تحصيل رسوم من حسابك على Google Cloud Platform مقابل الموارد المستخدَمة في هذا الدرس التطبيقي حول الترميز، عليك حذف الجهاز الظاهري.
gcloud bigtable instances delete $INSTANCE_ID
المواضيع التي تناولناها
- تصميم المخطط
- إعداد مثيل وجدول ومجموعة
- استيراد ملفات التسلسل باستخدام Dataflow
- الاستعلام باستخدام عملية بحث، وعملية مسح ضوئي، وعملية مسح ضوئي باستخدام فلتر، وعملية مسح ضوئي بنطاقات متعددة
الخطوات التالية
- يمكنك الاطّلاع على مزيد من المعلومات عن Cloud Bigtable في المستندات.
- جرِّب بنفسك ميزات Google Cloud Platform الأخرى. يمكنك الاطّلاع على البرامج التعليمية.
- كيفية مراقبة بيانات السلسلة الزمنية باستخدام عملية الدمج مع OpenTSDB