Redis นอกจากจะเก็บข้อมูลที่เป็น key and value แล้วก็ยังมีอีกความสามารถพิเศษอีกอย่างนึง คือสามารถใช้เก็บข้อมูลทางภูมิศาตร์ ซึ่งจะเก็บข้อมูลที่เป็น latitude กับ longitude ได้ด้วย blog นี้เราจะมาดูว่ามันคืออะไร ใช้งานอย่างไร แล้ว use cases ที่เราเอาไปใช้งานได้มีอะไรบ้าง

Image alt

Background

ถ้าเรามีโจทย์มาว่าต้องออกแบบระบบให้เก็บข้อมูลที่เป็นพิกัดของสถานที่ ลงใน database เราจะเก็บมันยังไงครับ ตัวอย่างเช่น ผมต้องการเก็บตำแหน่งของสาขาของร้านสะดวกซื้อ 7-11 ทั้งหมดในกรุงเทพ แบบตัวอย่างข้อมูลข้างล่างนี้

latitudelongitudelocation
13.75759654737684100.564266442321887-11 Rama 9
13.803052551902061100.555369333301037-11 Phahonyothin
13.779830852003741100.543717351418987-11 Ari

ถ้าเราเก็บ Latitude, Longitude, Location แยกเป็นแต่ละคอลัมน์ หรือ field ใน database แบบ ตารางข้างบน ก็ดูไม่มีปัญหาอะไรใช่ไหมครับ เราสามารถ query ตำแหน่งของสถานที่ที่เราต้องการอยากรู้ได้

แต่ถ้าเราต้องการอยากรู้ว่า จากตำแหน่งที่เรายืนอยู่เนี่ย มี 7-11 ไหนที่ไกล้ที่สุด (คล้ายๆ กับเวลาเสิร์ชหา 7-11 ใน Google Maps) เราจะ query มันยังไงครับ 🤔

ณ จุดนี้แหละครับ ที่เราต้องการ data structure ที่มันสามารถทำงานร่วมกับข้อมูลที่เป็นแบบ geospatial data ได้

Redis Geospatial

Redis มี built-in feature ที่สามารถให้เราบันทึกข้อมูลทางภูมิศาตร์ (Geospatial data) ลงได้เลย โดยที่ไม่ต้องมีการ install plugin ใดๆเพิ่มเติม ประโยชน์หลักๆในการใช้งาน feature นี้ก็คือ

  • Real time tracking: สามารถใช้ Redis ในการเก็บ real time gps location ของสิ่งที่เราสนใจ เพราะ Redis เป็น in-memory อยู่แล้ว ทำให้การบันทึก การอ่านข้อมูล รวดเร็ว ยกตัวอย่างเช่นบริษัท logistic อาจจะต้องการ track ว่ารถส่งของตอนนี้อยุ่พิกัดไหนบ้าง ในแต่ละช่วงเวลา
  • Proximity service: สามารถค้นหาสถานที่ที่เราสนใจ อาจจะเป็นสถานที่ใกล้จากจุดที่เราอยู่ เหมือนตัวอย่าง 7-11 ด้านบนที่ได้กล่าวไปแล้ว

How to use

เราจะลองใช้งาน Redis geospatial กับตัวอย่างข้อมูลสถานที่สาขาของ 7-11 ด้านบนกันครับ

Insert

ในขั้นแรกสุดเราต้องทำการ insert ข้อมูลของสถานที่ที่เราต้องการเก็บลงไปใน Redis ครับ ซึ่งเราจะใช้คำสั่ง GEOADD โดย syntax ในการเพิ่มข้อมูลจะเป็นดังนี้ครับ

GEOADD $KEY $LONGITUDE $LATITUDE $NAME

สมมติว่าผมต้องการเพิ่มข้อมูลของสถานที่ทั้ง 3 สาขาของ 7-11 เราจะต้องเพิ่มข้อมูลโดยใช้คำสั่ง

GEOADD 7-11:branches 100.56426644232188 13.75759654737684 "7-11 Rama 9"
GEOADD 7-11:branches 100.55536933330103 13.803052551902061 "7-11 Phahonyothin"
GEOADD 7-11:branches 100.54371735141898 13.779830852003741 "7-11 Ari"

สิ่งเกิดขึ้นก็คือ redis จะทำการสร้าง key ใหม่ชื่อ 7-11:branches ใน memory ส่วน value ของ key นี้จะเป็น sorted set ของ 3 สาขาที่เราได้เพิ่มเข้าไปครับ

Query

ส่วนวิธีการ query ข้อมูลก็ทำได้ง่ายมากโดยการใช้คำสั่ง GEORADIUS โดย syntax ในการใช้งานจะเป็นดังนี้

GEORADIUS $KEY $LONGITUDE $LATITUDE $RADIUS $RADIUS-UNIT

ตัวอย่างการใช้งานเช่น ถ้าสมมติตอนนี้ผมอยู่ที่ตึกฟอร์จูนทาวน์ และพิกัดที่ผมอยู่ปัจจุบันคือ lat, long = 13.758449840108376, 100.56490556561921 ผมอยากรู้ว่าในรัศมี 700 เมตรมี 7-11 บ้างไหมเราจะ query โดยใช้คำสั่ง

redis> GEORADIUS 7-11:branches 100.56490556561921 13.758449840108376 700 m
1) "Rama 9"

ซึ่ง Redis จะทำการ query โดยใช้พิกัดที่เราให้ไปเป็นที่ตั้ง แล้วทำการค้นหาสาขาของ 7-11 ทั้งหมดในรัศมีที่เรากำหนด หลังจากนั้นจะทำการ return สถานที่ทั้งหมดของสาขาที่อยู่ในเงื่อนไขที่เรากำหนดไว้ ซี่งในที่นี้เราจะได้สาขา Rama 9 มาครับ

ในกรณีที่มีหลาย ๆ locations อยู่ใน radius ที่กำหนดไป ​Redis จะส่งค่าทั้งหมดกลับมาให้ เช่นถ้าสมมติผมอยู่ที่เดิมแต่อยากเพิ่ม รัศมีเป็น 100 กิโลเมตร

redis> GEORADIUS 7-11:branches 100.56490556561921 13.758449840108376 100 km
1) "7-11 Ari"
2) "Rama 9"
3) "7-11 Phahonyothin"

นอกจากนี้เรายังสามารถรู้ระยะห่างจากจุดที่เราอยู่ไปยังแต่ละสถานที่ได้ ด้วยการเพิ่ม option WITHDIST

redis> GEORADIUS 7-11:branches 100.56490556561921 13.758449840108376 100 km WITHDIST
1) 1) "7-11 Ari"
   2) "3.3006"
2) 1) "Rama 9"
   2) "0.1176"
3) 1) "7-11 Phahonyothin"
   2) "5.0669"

ในทำนองเดียวกัน ถ้าเราอยากรู้ระยะทางระหว่างสถานที่สองแห่ง เช่นสาขาหนึ่งของ 7-11 ไปอีกสาขาหนึ่งเราสามารถใช้ GEODIST ในการคำนวนให้เราได้ครับ ตัวอย่างเช่น

redis>  GEODIST 7-11:branches "7-11 Ari" "7-11 Phahonyothin" km
"2.8733"

พอจะเห็นภาพกันแล้วใช่ไหมครับ และนอกเหนือจากคำสั่งที่ได้เราได้ลองเล่นไป ยังมี command อื่นๆ ให้เราเลือกใช้งานได้อีกมากมาย ตามความเหมาะสมของแต่ละความต้องการของระบบครับ ซึ่งสามารถดู command ทั้งหมดได้ที่ Official website ของ redis เลย เช่น

Summary

Redis geospatial เป็น feature หนึ่งของ redis ที่ช่วยให้เราทำงานกับข้อมูลทางภูมิศาสตร์ เก็บข้อมูลพิกัดที่เป็นทศนิยมของ Latitude กับ Longitude และนำข้อมูลที่เก็บมาใช้งานได้อย่างง่ายดาย สามารถทำไปประยุกต์ใช้ได้หลายรูปแบบ

ส่วนตัวผมได้นำ Redis Geospatial ไปใช้กับงาน production มาสักพัก แล้วรู้สึกว่ามัน efficient มากๆ การที่เป็น built-in feature ทำให้อะไรๆ ง่ายขึ้นมาก เพราะปกติเราก็ใช้ redis เป็น caching option อยุ่แล้ว การนำ geospatial มาใส่ใน redis สามารถทำได้เลย ไม้ต้องมีการ config ใดๆ สรุปก็คือมันทำให้ชีวิต developer เราง่ายขึ้นมากๆครับ 🤩 🤩 🤩

Reference: