ข้อมูลเบื้องต้นเกี่ยวกับ Cloud Bigtable

1. บทนำ

ในโค้ดแล็บนี้ คุณจะได้ทำความรู้จักกับการใช้ Cloud Bigtable กับ Java HBase client

คุณจะได้เรียนรู้วิธีต่อไปนี้

  • หลีกเลี่ยงข้อผิดพลาดที่พบบ่อยในการออกแบบสคีมา
  • นำเข้าข้อมูลในไฟล์ลำดับ
  • ค้นหาข้อมูล

เมื่อเสร็จแล้ว คุณจะมีแผนที่หลายรายการที่แสดงข้อมูลรถประจำทางของนิวยอร์กซิตี้ เช่น คุณจะสร้างฮีตแมปของการเดินทางด้วยรถประจำทางในแมนฮัตตันดังนี้

7349d94f7d41f1d1.png

คุณจะให้คะแนนประสบการณ์การใช้ Google Cloud Platform เท่าใด

ผู้ฝึกหัด ขั้นกลาง ผู้ชำนาญ

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านผ่านๆ เท่านั้น อ่านและทำแบบฝึกหัดให้เสร็จ

2. เกี่ยวกับชุดข้อมูล

คุณจะเห็นชุดข้อมูลเกี่ยวกับรถโดยสารในนิวยอร์กซิตี้ มีเส้นทางรถประจำทางมากกว่า 300 เส้นทางและยานพาหนะ 5,800 คันที่วิ่งตามเส้นทางเหล่านั้น ชุดข้อมูลของเราคือบันทึกที่มีชื่อปลายทาง รหัสยานพาหนะ ละติจูด ลองจิจูด เวลาที่คาดว่าจะถึง และเวลาที่กำหนดถึง ชุดข้อมูลประกอบด้วยสแนปชอตที่ถ่ายทุกๆ 10 นาทีโดยประมาณในเดือนมิถุนายน 2017

3. การออกแบบสคีมา

หากต้องการให้ Cloud Bigtable ทำงานได้เต็มประสิทธิภาพ คุณต้องพิจารณาอย่างรอบคอบเมื่อออกแบบสคีมา ข้อมูลใน Cloud Bigtable จะจัดเรียงโดยอัตโนมัติตามลำดับอักษร ดังนั้นหากออกแบบสคีมาได้ดี การค้นหาข้อมูลที่เกี่ยวข้องจะมีประสิทธิภาพมาก Cloud Bigtable อนุญาตให้ใช้การค้นหาโดยใช้การค้นหาแบบจุดตามคีย์ประจำแถวหรือการสแกนช่วงแถวที่แสดงผลชุดแถวที่ต่อเนื่องกัน อย่างไรก็ตาม หากไม่ได้วางแผนสคีมาไว้อย่างดี คุณอาจต้องต่อเติมการค้นหาหลายแถว หรือที่แย่กว่านั้นคือต้องทำการสแกนตารางทั้งหมด ซึ่งเป็นการดำเนินการที่ช้ามาก

วางแผนการค้นหา

ข้อมูลของเรามีข้อมูลหลากหลาย แต่สำหรับโค้ดแล็บนี้ คุณจะใช้ตำแหน่งและจุดหมายปลายทางของรถประจำทาง

คุณสามารถใช้ข้อมูลดังกล่าวเพื่อทำการค้นหาต่อไปนี้ได้

  • รับตำแหน่งของรถประจำทางคันเดียวในช่วงเวลาที่กำหนด
  • ดูข้อมูลของเส้นทางรถประจำทางหรือรถประจำทางที่เฉพาะเจาะจงใน 1 วัน
  • ค้นหารถบัสทั้งหมดในสี่เหลี่ยมผืนผ้าบนแผนที่
  • รับตำแหน่งปัจจุบันของรถโดยสารทั้งหมด (หากคุณนำเข้าข้อมูลนี้แบบเรียลไทม์)

การค้นหาชุดนี้ไม่สามารถดำเนินการร่วมกันได้อย่างเหมาะสม ตัวอย่างเช่น หากจัดเรียงตามเวลา คุณจะทำการสแกนตามสถานที่ตั้งไม่ได้โดยไม่ต้องทำการสแกนตารางแบบเต็ม คุณต้องจัดลำดับความสำคัญตามคำค้นหาที่คุณใช้บ่อยที่สุด

สำหรับโค้ดแล็บนี้ คุณจะมุ่งเน้นที่การเพิ่มประสิทธิภาพและการเรียกใช้ชุดคำค้นหาต่อไปนี้

  • ดูตำแหน่งของยานพาหนะที่เฉพาะเจาะจงในช่วงเวลา 1 ชั่วโมง
  • รับตำแหน่งของรถประจำทางทั้งสายในระยะเวลา 1 ชั่วโมง
  • ดูตำแหน่งของรถบัสทั้งหมดในแมนแฮตตันได้ภายใน 1 ชั่วโมง
  • ดูตำแหน่งล่าสุดของรถประจำทางทั้งหมดในแมนฮัตตันได้ใน 1 ชั่วโมง
  • รับตำแหน่งของเส้นทางรถประจำทางทั้งสายตลอดทั้งเดือน
  • ดูตำแหน่งของรถประจำทางทั้งสายที่มีจุดหมายปลายทางหนึ่งๆ ได้ภายใน 1 ชั่วโมง

ออกแบบคีย์ประจำแถว

สำหรับ Codelab นี้ คุณจะทำงานกับชุดข้อมูลแบบคงที่ แต่จะออกแบบสคีมาเพื่อความสามารถในการปรับขนาด คุณจะออกแบบสคีมาที่ช่วยให้สตรีมข้อมูลรถประจำทางเพิ่มเติมลงในตารางได้และยังคงทำงานได้ดี

ต่อไปนี้คือสคีมาที่เสนอสำหรับคีย์แถว

[บริษัทรถประจำทาง/สายรถประจำทาง/การประทับเวลาที่ปัดเศษลงเป็นชั่วโมง/รหัสยานพาหนะ] แต่ละแถวมีข้อมูล 1 ชั่วโมง และแต่ละเซลล์มีข้อมูลหลายเวอร์ชันที่ประทับเวลา

สำหรับโค้ดแล็บนี้ คุณจะใช้ตระกูลคอลัมน์เดียวเพื่อให้ง่าย ตัวอย่างมุมมองของลักษณะข้อมูลมีดังนี้ ระบบจะจัดเรียงข้อมูลตามคีย์แถว

คีย์แถว

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" ที่มุมบนขวา

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 มาพร้อมกับเครื่องมือที่คุณจะใช้ในโค้ดแล็บนี้ ซึ่งได้แก่ เครื่องมือบรรทัดคำสั่ง 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/*

ตรวจสอบการนำเข้า

คุณตรวจสอบงานได้ใน UI ของ Cloud Dataflow นอกจากนี้ คุณยังดูโหลดในอินสแตนซ์ Cloud Bigtable ได้ด้วยUI การตรวจสอบ การนำเข้าทั้งหมดจะใช้เวลา 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 ให้เรียกใช้คำสั่งต่อไปนี้เพื่อดูรายการละติจูดและลองจิจูดของรถประจำทางคันนั้นในช่วง 1 ชั่วโมง

mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \
-Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \
-Dquery=lookupVehicleInGivenHour

คุณสามารถคัดลอกและวางละติจูดและลองจิจูดลงในแอป MapMaker เพื่อแสดงผลลัพธ์เป็นภาพ หลังจากผ่านไป 2-3 เลเยอร์ ระบบจะแจ้งให้คุณสร้างบัญชีฟรี คุณจะสร้างบัญชีหรือลบเลเยอร์ที่มีอยู่ก็ได้ 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

แอป Map Maker สามารถแสดงรายการหลายรายการพร้อมกันได้ คุณจึงดูได้ว่ารถบัสคันใดเป็นยานพาหนะจากคำค้นหาแรกที่คุณเรียกใช้

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

หากคัดลอกผลลัพธ์ลงใน Map Maker คุณจะดูฮีตแมปของเส้นทางรถประจำทางได้ ก้อนสีส้มแสดงจุดแวะพัก และก้อนสีแดงสดแสดงจุดเริ่มต้นและจุดสิ้นสุดของเส้นทาง

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

การเปรียบเทียบฮีตแมป 2 รายการจะช่วยให้คุณเห็นความแตกต่างของเส้นทาง รวมถึงสังเกตความแตกต่างในการกำหนดเวลาได้ การตีความข้อมูลอย่างหนึ่งคือรถประจำทางที่วิ่งไปทางทิศตะวันตกจะถูกหยุดบ่อยขึ้น โดยเฉพาะเมื่อเข้าสู่เซ็นทรัลพาร์ก และบนรถบัสที่มุ่งหน้าไปทางตะวันออก คุณจะไม่เห็นจุดคอขวดมากนัก

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
  • การค้นหาด้วยการค้นหา การสแกน การสแกนด้วยตัวกรอง และการสแกนหลายช่วง

ขั้นตอนถัดไป