מבוא ל-Cloud Bigtable

1. מבוא

ב-Codelab הזה, תקבלו היכרות עם השימוש ב-Cloud Bigtable עם לקוח Java HBase.

כאן מוסבר איך

  • נמנעים מטעויות נפוצות בעיצוב הסכימה
  • ייבוא נתונים בקובץ רצף
  • הרצת שאילתות על הנתונים

כשתסיימו, יהיו לכם כמה מפות שמציגות נתוני אוטובוסים של תל אביב. לדוגמה, יוצרים מפת חום של נסיעות באוטובוסים במנהטן:

7349d94f7d41f1d1.png

איזה דירוג מגיע לדעתך לחוויית השימוש ב-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". בפינה השמאלית העליונה.

a74d156ca7862b28.png

כדי שיהיה קל יותר להעתיק ולהדביק את פקודות 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 הזה כולל תצוגה חזותית של כל שלב, אם אתם רק רוצים לעקוב אחריו. זאת התוצאה של השאילתה הראשונה:

f1a1fac6051c6210.png

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

c18a4ac6522d08a2.png

אפליקציית 'יוצר המפות' יכולה להציג מספר רשימות בו-זמנית, כך שתוכלו לראות אילו מהאוטובוסים הם הרכב לפי השאילתה הראשונה שהרצתם.

234c1b51e3b201e.png

שינוי מעניין בשאילתה הזו הוא הצגת הנתונים מהחודש כולו של קו האוטובוס 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 האדומים הבהירים הם ההתחלה והסיום של המסלול.

346f52e61b3d8902.png

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

אוטובוסים שנוסעים מזרחה

76f6f62096a6847a.png

אוטובוסים בכיוון מערב

2b5771ee9046399f.png

השוואה בין שתי מפות החום מאפשרת לך לראות את ההבדלים במסלולים ולראות הבדלים בקצב. פרשנות אחת לנתונים היא שבמסלול לכיוון מערב, האוטובוסים נעצרים יותר, במיוחד בכניסה לסנטרל פארק. ובאוטובוסים שנוסעים מזרחה, לא רואים הרבה נקודות חנק.

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

7349d94f7d41f1d1.png

11. סיום

פינוי נפח אחסון כדי להימנע מחיובים

כדי להימנע מצבירת חיובים בחשבון Google Cloud Platform עבור המשאבים ששימשו ב-Codelab הזה, צריך למחוק את המכונה.

gcloud bigtable instances delete $INSTANCE_ID

אילו נושאים דיברנו?

  • עיצוב סכימה
  • הגדרת מכונה, טבלה ומשפחה
  • ייבוא קובצי רצף באמצעות Dataflow
  • שליחת שאילתה באמצעות חיפוש, סריקה, סריקה עם מסנן וסריקה במספר טווחים

השלבים הבאים