1. מבוא
ב-Codelab הזה, תקבלו היכרות עם השימוש ב-Cloud Bigtable עם לקוח Java HBase.
כאן מוסבר איך
- נמנעים מטעויות נפוצות בעיצוב הסכימה
- ייבוא נתונים בקובץ רצף
- הרצת שאילתות על הנתונים
כשתסיימו, יהיו לכם כמה מפות שמציגות נתוני אוטובוסים של תל אביב. לדוגמה, יוצרים מפת חום של נסיעות באוטובוסים במנהטן:
איזה דירוג מגיע לדעתך לחוויית השימוש ב-Google Cloud Platform?
איך תשתמשו במדריך הזה?
2. מידע על מערך הנתונים
תעיינו במערך נתונים לגבי אוטובוסים בעיר ניו יורק. במסלולים האלה יש יותר מ-300 מסלולי אוטובוסים ו-5,800 כלי רכב. מערך הנתונים שלנו הוא יומן שכולל את שם היעד, מזהה הרכב, קו הרוחב, קו האורך, שעת ההגעה הצפויה ושעת ההגעה המתוכננת. מערך הנתונים מורכב מתמונות מצב שצולמו בכל 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 המובנה, שפותחים בלחיצה על "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 מגיע עם הכלים שתשתמש בהם ב-Codelab הזה, כלי שורת הפקודה של 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. ייבוא נתונים
מייבאים קבוצה של קובצי רצף עבור ה-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));
התוצאה צריכה להכיל את המיקום העדכני ביותר של האוטובוס באותה שעה. אבל אתם רוצים לראות את כל המיקומים, לכן צריך להגדיר את מספר הגרסאות המקסימלי בבקשת השליפה.
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
אפליקציית 'יוצר המפות' יכולה להציג מספר רשימות בו-זמנית, כך שתוכלו לראות אילו מהאוטובוסים הם הרכב לפי השאילתה הראשונה שהרצתם.
שינוי מעניין בשאילתה הזו הוא הצגת הנתונים מהחודש כולו של קו האוטובוס 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, אפשר להציג מפת חום של מסלול האוטובוס. ה-blobs הכתומים מציינים את התחנות, וה-blobs האדומים הבהירים הם ההתחלה והסיום של המסלול.
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