۱. مقدمه
در این آزمایشگاه کد، شما با نحوه استفاده از Cloud Bigtable با کلاینت Java HBase آشنا خواهید شد.
یاد خواهید گرفت که چگونه
- از اشتباهات رایج در طراحی اسکیما اجتناب کنید
- وارد کردن دادهها در یک فایل توالی
- دادههای خود را پرسوجو کنید
وقتی کارتان تمام شد، چندین نقشه خواهید داشت که دادههای اتوبوسهای شهر نیویورک را نشان میدهند. برای مثال، این نقشه حرارتی از سفرهای اتوبوس در منهتن را ایجاد خواهید کرد:

تجربه خود را در استفاده از پلتفرم ابری گوگل چگونه ارزیابی میکنید؟
چگونه از این آموزش استفاده خواهید کرد؟
۲. درباره مجموعه دادهها
شما به یک مجموعه داده در مورد اتوبوسهای شهر نیویورک نگاه خواهید کرد. بیش از ۳۰۰ مسیر اتوبوس و ۵۸۰۰ وسیله نقلیه در این مسیرها وجود دارد. مجموعه داده ما یک گزارش است که شامل نام مقصد، شناسه وسیله نقلیه، عرض جغرافیایی، طول جغرافیایی، زمان رسیدن مورد انتظار و زمان رسیدن برنامهریزی شده است. این مجموعه داده از عکسهای فوری گرفته شده در هر ۱۰ دقیقه برای ژوئن ۲۰۱۷ تشکیل شده است.
۳. طراحی طرحواره
برای اینکه بهترین عملکرد را از Cloud Bigtable دریافت کنید، باید هنگام طراحی طرحواره خود با دقت عمل کنید. دادهها در Cloud Bigtable به صورت خودکار بر اساس واژگان مرتب میشوند، بنابراین اگر طرحواره خود را به خوبی طراحی کنید، پرسوجو برای دادههای مرتبط بسیار کارآمد خواهد بود. Cloud Bigtable امکان پرسوجو با استفاده از جستجوی نقطهای بر اساس کلید سطر یا اسکنهای محدوده سطر را فراهم میکند که مجموعهای پیوسته از سطرها را برمیگرداند. با این حال، اگر طرحواره شما به خوبی طراحی نشده باشد، ممکن است مجبور شوید چندین جستجوی سطر را کنار هم قرار دهید یا بدتر از آن، اسکن کامل جدول را انجام دهید که عملیات بسیار کندی است.
سوالات را برنامهریزی کنید
دادههای ما اطلاعات متنوعی دارند، اما برای این آزمایشگاه کد، شما از موقعیت مکانی و مقصد اتوبوس استفاده خواهید کرد.
با این اطلاعات، میتوانید این کوئریها را انجام دهید:
- موقعیت مکانی یک اتوبوس را در یک ساعت مشخص دریافت کنید.
- دادههای مربوط به یک خط اتوبوس یا یک اتوبوس خاص را در طول یک روز دریافت کنید.
- تمام اتوبوسهای داخل یک مستطیل را روی نقشه پیدا کنید.
- مکان فعلی همه اتوبوسها را دریافت کنید (اگر این دادهها را به صورت بلادرنگ دریافت میکردید).
این مجموعه از پرسوجوها را نمیتوان به طور بهینه با هم انجام داد. برای مثال، اگر مرتبسازی را بر اساس زمان انجام میدهید، نمیتوانید بدون انجام اسکن کامل جدول، اسکن را بر اساس مکان انجام دهید. شما باید بر اساس پرسوجوهایی که معمولاً اجرا میکنید، اولویتبندی کنید.
برای این آزمایشگاه کد، شما بر بهینهسازی و اجرای مجموعه کوئریهای زیر تمرکز خواهید کرد:
- مکانهای یک وسیله نقلیه خاص را در طول یک ساعت دریافت کنید.
- مکانهای کل خط اتوبوس را در طول یک ساعت دریافت کنید.
- مکان تمام اتوبوسهای منهتن را در عرض یک ساعت دریافت کنید.
- جدیدترین مکانهای تمام اتوبوسها در منهتن را در عرض یک ساعت دریافت کنید.
- مکانهای کل خط اتوبوس را در طول ماه دریافت کنید.
- مکانهای کل خط اتوبوس با یک مقصد خاص را در طول یک ساعت دریافت کنید.
طراحی کلید ردیف
برای این آزمایشگاه کد، شما با یک مجموعه داده استاتیک کار خواهید کرد، اما یک طرحواره برای مقیاسپذیری طراحی خواهید کرد. شما طرحی را طراحی خواهید کرد که به شما امکان میدهد دادههای گذرگاه بیشتری را به جدول منتقل کنید و همچنان عملکرد خوبی داشته باشید.
طرح پیشنهادی برای کلید ردیف به صورت زیر است:
[شرکت اتوبوسرانی/خط اتوبوسرانی/مهر زمانی گرد شده به پایین به ساعت/شناسه وسیله نقلیه]. هر ردیف حاوی یک ساعت داده است و هر سلول چندین نسخه با مهر زمانی از دادهها را در خود جای داده است.
برای این کد، برای ساده نگه داشتن همه چیز، از یک خانواده ستون استفاده خواهید کرد. در اینجا یک نمای نمونه از نحوه نمایش دادهها آورده شده است. دادهها بر اساس کلید سطر مرتب شدهاند.
کلید ردیف | رجوع کنید به: موقعیت مکانی خودرو. عرض جغرافیایی | رجوع کنید به: موقعیت مکانی خودرو. طول جغرافیایی | ... |
MTA/M86-SBS/1496275200000/NYCT_5824 | ۴۰.۷۸۱۲۱۲ @۲۰:۵۲:۵۴.۰۰ ۴۰.۷۷۶۱۶۳ @۲۰:۴۳:۱۹.۰۰ ۴۰.۷۷۸۷۱۴ @۲۰:۳۳:۴۶.۰۰ | -۷۳.۹۶۱۹۴۲ @۲۰:۵۲:۵۴.۰۰ -۷۳.۹۴۶۹۴۹ @۲۰:۴۳:۱۹.۰۰ -۷۳.۹۵۳۷۳۱ @۲۰:۳۳:۴۶.۰۰ | ... |
MTA/M86-SBS/1496275200000/NYCT_5840 | ۴۰.۷۸۰۶۶۴ @۲۰:۱۳:۵۱.۰۰ ۴۰.۷۸۸۴۱۶ @۲۰:۰۳:۴۰.۰۰ | -۷۳.۹۵۸۳۵۷ @۲۰:۱۳:۵۱.۰۰ -۷۳.۹۷۶۷۴۸ @۲۰:۰۳:۴۰.۰۰ | ... |
MTA/M86-SBS/1496275200000/NYCT_5867 | ۴۰.۷۸۰۲۸۱ @۲۰:۵۱:۴۵.۰۰ ۴۰.۷۷۹۹۶۱ @۲۰:۴۳:۱۵.۰۰ ۴۰.۷۸۸۴۱۶ @۲۰:۳۳:۴۴.۰۰ | -۷۳.۹۴۶۸۹۰ @۲۰:۵۱:۴۵.۰۰ -۷۳.۹۵۹۴۶۵ @۲۰:۴۳:۱۵.۰۰ -۷۳.۹۷۶۷۴۸ @۲۰:۳۳:۴۴.۰۰ | ... |
... | ... | ... | ... |
۴. ایجاد نمونه، جدول و خانواده
در مرحله بعد، یک جدول Cloud Bigtable ایجاد خواهید کرد.
ابتدا، یک پروژه جدید ایجاد کنید. از Cloud Shell داخلی استفاده کنید که میتوانید با کلیک روی دکمه «Activate 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 که از قبل نصب شدهاند، ارائه میشود.
با اجرای این دستور، APIهای Cloud Bigtable را فعال کنید.
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
۵. وارد کردن دادهها
مجموعهای از فایلهای توالی را برای این آزمایشگاه کد از 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 خود را با رابط کاربری نظارت آن مشاهده کنید. کل فرآیند وارد کردن دادهها باید ۵ دقیقه طول بکشد.
۶. کد را دریافت کنید
git clone https://github.com/googlecodelabs/cbt-intro-java.git cd cbt-intro-java
با اجرای دستورات زیر به جاوا ۱۱ تغییر دهید:
sudo update-java-alternatives -s java-1.11.0-openjdk-amd64 && export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
۷. انجام جستجو
اولین پرسوجویی که انجام خواهید داد، یک جستجوی ساده در ردیفها است. شما دادههای مربوط به یک اتوبوس در خط M86-SBS را در تاریخ ۱ ژوئن ۲۰۱۷ از ساعت ۱۲:۰۰ بامداد تا ۱:۰۰ بامداد دریافت خواهید کرد. در آن زمان، وسیله نقلیهای با شناسه 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));
نتیجه باید شامل جدیدترین موقعیت مکانی اتوبوس در آن ساعت باشد. اما شما میخواهید همه مکانها را ببینید، بنابراین حداکثر تعداد نسخهها را در درخواست دریافت تنظیم کنید.
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 پیست کنید تا نتایج را تجسم کنید. پس از چند لایه، به شما میگوید که یک حساب کاربری رایگان ایجاد کنید. میتوانید یک حساب کاربری ایجاد کنید یا لایههای موجود را حذف کنید. این codelab شامل یک تجسم برای هر مرحله است، اگر فقط میخواهید ادامه دهید. در اینجا نتیجه این پرس و جو اول آمده است:

۸. اسکن انجام دهید
حالا، بیایید تمام دادههای مربوط به خط اتوبوس را برای آن ساعت مشاهده کنیم. کد اسکن بسیار شبیه به کد دریافت است. شما به اسکنر یک موقعیت شروع میدهید و سپس مشخص میکنید که فقط ردیفهایی برای خط اتوبوس M86-SBS را در ساعتی که با مهر زمانی ۱۴۹۶۲۷۵۲۰۰۰۰۰ نشان داده شده است، میخواهید.
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

اپلیکیشن Map Maker میتواند چندین لیست را به طور همزمان نمایش دهد، بنابراین میتوانید ببینید کدام یک از اتوبوسها، وسیله نقلیهای است که در اولین جستجوی خود به آن اشاره کردید.

یک تغییر جالب در این پرسوجو، مشاهده کل دادههای ماه برای خط باس 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 کپی کنید، میتوانید یک نقشه حرارتی از مسیر اتوبوس مشاهده کنید. حبابهای نارنجی ایستگاهها را نشان میدهند و حبابهای قرمز روشن شروع و پایان مسیر هستند.

۹. فیلترها را معرفی کنید
در مرحله بعد، اتوبوسهایی که به سمت شرق و اتوبوسهایی که به سمت غرب میروند را فیلتر میکنید و برای هر کدام یک نقشه حرارتی جداگانه ایجاد میکنید.
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
اتوبوسهایی که به سمت شرق میروند

اتوبوسهایی که به سمت غرب میروند

با مقایسه دو نقشه حرارتی، میتوانید تفاوتهای مسیرها و همچنین تفاوتهای سرعت را مشاهده کنید. یک تفسیر از دادهها این است که در مسیری که به سمت غرب میرود، اتوبوسها بیشتر متوقف میشوند، به خصوص هنگام ورود به پارک مرکزی. و در اتوبوسهایی که به سمت شرق میروند، واقعاً نقاط انسداد زیادی نمیبینید.
۱۰. انجام اسکن چند محدودهای
برای پرسش نهایی، به موردی میپردازید که تعداد زیاد خطوط اتوبوس در یک منطقه برایتان مهم است:
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

۱۱. تمام کنید
برای جلوگیری از هزینهها، تمیزکاری کنید
برای جلوگیری از تحمیل هزینه به حساب پلتفرم گوگل کلود خود برای منابع استفاده شده در این آزمایشگاه کد، باید نمونه خود را حذف کنید.
gcloud bigtable instances delete $INSTANCE_ID
آنچه ما پوشش دادهایم
- طراحی طرحواره
- راهاندازی یک نمونه، جدول و فمیلی
- وارد کردن فایلهای توالی با جریان داده
- پرس و جو با جستجو، اسکن، اسکن با فیلتر و اسکن چند محدودهای
مراحل بعدی
- برای کسب اطلاعات بیشتر در مورد Cloud Bigtable به مستندات مراجعه کنید.
- سایر ویژگیهای پلتفرم ابری گوگل را خودتان امتحان کنید. نگاهی به آموزشهای ما بیندازید.
- یاد بگیرید چگونه دادههای سری زمانی را با ادغام OpenTSDB نظارت کنید