1. מבוא
בשיעור הזה תלמדו איך להשתמש ב-Cloud Bigtable עם לקוח Java HBase.
מה תלמדו
- איך להימנע מטעויות נפוצות בעיצוב סכימה
- ייבוא נתונים בקובץ רצף
- שאילתת נתונים
בסיום, יהיו לכם כמה מפות שיוצגו בהן נתוני אוטובוסים בניו יורק. לדוגמה, תיצרו את מפת החום הזו של נסיעות באוטובוס במנהטן:

איך היית מדרג את חוויית השימוש שלך ב-Google Cloud Platform?
איך תשתמשו במדריך הזה?
2. מידע על מערך הנתונים
יוצג לכם מערך נתונים על אוטובוסים בניו יורק. יש יותר מ-300 מסלולי אוטובוסים ו-5,800 כלי רכב שנוסעים במסלולים האלה. מערך הנתונים שלנו הוא יומן שכולל את שם היעד, מזהה הרכב, קו הרוחב, קו האורך, זמן ההגעה הצפוי וזמן ההגעה המתוכנן. מערך הנתונים מורכב מקובצי snapshot שצולמו בערך כל 10 דקות במהלך יוני 2017.
3. עיצוב סכימה
כדי להפיק את הביצועים הטובים ביותר מ-Cloud Bigtable, צריך לחשוב היטב כשמעצבים את הסכימה. הנתונים ב-Cloud Bigtable ממוינים אוטומטית לפי סדר מילוני, כך שאם מעצבים את הסכימה בצורה טובה, השאילתות לנתונים קשורים יעילות מאוד. ב-Cloud Bigtable אפשר להריץ שאילתות באמצעות חיפושים נקודתיים לפי מפתח שורה או סריקות של טווח שורות שמחזירות קבוצה רציפה של שורות. עם זאת, אם הסכימה לא מתוכננת היטב, יכול להיות שתצטרכו לחבר כמה חיפושים בשורות, או גרוע מכך, לבצע סריקות מלאות של הטבלה, שהן פעולות איטיות במיוחד.
תכנון השאילתות
הנתונים שלנו כוללים מגוון מידע, אבל ב-Codelab הזה תשתמשו במיקום וביעד של האוטובוס.
בעזרת המידע הזה, תוכלו להריץ את השאילתות הבאות:
- קבלת המיקום של אוטובוס יחיד בשעה מסוימת.
- לקבל נתונים של יום שלם לגבי קו אוטובוס או אוטובוס ספציפי.
- חיפוש כל האוטובוסים בתוך מלבן במפה.
- קבלת המיקומים הנוכחיים של כל האוטובוסים (אם הנתונים האלה מוזנים בזמן אמת).
אי אפשר לבצע את כל השאילתות האלה יחד בצורה אופטימלית. לדוגמה, אם אתם ממיינים לפי זמן, לא תוכלו לבצע סריקה לפי מיקום בלי לבצע סריקה מלאה של הטבלה. צריך לקבוע סדר עדיפויות לפי השאילתות שאתם מריצים הכי הרבה.
ב-Codelab הזה תתמקדו באופטימיזציה של קבוצת השאילתות הבאה ובהרצתה:
- קבלת המיקומים של רכב ספציפי במשך שעה.
- קבלת המיקומים של קו אוטובוס שלם במשך שעה.
- קבלת המיקומים של כל האוטובוסים במנהטן תוך שעה.
- קבלת המיקומים העדכניים ביותר של כל האוטובוסים במנהטן תוך שעה.
- קבלת המיקומים של קו אוטובוס שלם במהלך החודש.
- קבלת המיקומים של כל האוטובוסים בקו מסוים עם יעד מסוים במשך שעה.
עיצוב מפתח השורה
ב-Codelab הזה תעבדו עם מערך נתונים סטטי, אבל תתכננו סכימה למדרגיות. תעצבו סכימה שתאפשר לכם להזרים עוד נתונים של אוטובוסים לטבלה ועדיין להשיג ביצועים טובים.
הנה סכימה מוצעת למפתח השורה:
[חברת אוטובוסים/קו אוטובוס/חותמת זמן מעוגלת כלפי מטה לשעה/מזהה רכב]. כל שורה מכילה נתונים של שעה, ובכל תא יש כמה גרסאות של הנתונים עם חותמת זמן.
ב-codelab הזה נשתמש במשפחת עמודות אחת כדי לפשט את הדברים. כאן מוצגת דוגמה לתצוגה של הנתונים. הנתונים ממוינים לפי מפתח השורה.
מפתח שורה | 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 מותקנים מראש הכלים שבהם תשתמשו ב-Codelab הזה: כלי שורת הפקודה של Google Cloud, ממשק שורת הפקודה 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
אחרי שיוצרים את המופע, מאכלסים את קובץ התצורה של Cloud Bigtable ואז יוצרים טבלה ומשפחת עמודות על ידי הרצת הפקודות הבאות:
echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf
5. ייבוא נתונים
מייבאים קבוצה של קבצים רציפים ל-codelab הזה מ-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 מ-00:00 עד 01: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. אחרי כמה שכבות, תתבקשו ליצור חשבון בחינם. אתם יכולים ליצור חשבון או פשוט למחוק את השכבות הקיימות. ב-Codelab הזה יש תרשים לכל שלב, אם אתם רוצים רק לעקוב אחרי ההוראות. זו התוצאה של השאילתה הראשונה:

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

באפליקציית 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
אם מעתיקים את התוצאות ל-Map Maker, אפשר לראות מפת חום של מסלול האוטובוס. הכתמים הכתומים מציינים את העצירות, והכתמים האדומים הבהירים מציינים את ההתחלה והסוף של המסלול.

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 על המשאבים שבהם השתמשתם ב-codelab הזה, אתם צריכים למחוק את המכונה.
gcloud bigtable instances delete $INSTANCE_ID
מה נכלל
- עיצוב סכימה
- הגדרת מופע, טבלה ומשפחה
- ייבוא קבצים של רצפים באמצעות Dataflow
- שאילתות עם חיפוש, סריקה, סריקה עם מסנן וסריקה של כמה טווחים
השלבים הבאים
- מידע נוסף על Cloud Bigtable זמין במאמרי העזרה.
- אתם יכולים להתנסות בעצמכם בתכונות אחרות של Google Cloud Platform. מומלץ לעיין במדריכים שלנו.
- איך עוקבים אחרי נתונים של סדרות זמן באמצעות השילוב של OpenTSDB