Flash Sale! Up to 40% off on unlimited courses, tutorials and creative asset downloads Up to 40% off on unlimited assets SAVE NOW
Advertisement
  1. Code
  2. Node.js
Code

Membangun Pencari Toko Dengan Node.js dan Redis

by
Difficulty:IntermediateLength:LongLanguages:

Indonesian (Bahasa Indonesia) translation by Ilham Saputra (you can also view the original English article)

Kunjungi situs web untuk rantai restoran atau toko apa pun dan Anda kemungkinan akan menemukan "pencari toko": sebuah laman kecil yang tampak sederhana tempat Anda memasukkan alamat atau kode postingan/pos dan itu menyediakan lokasi di dekat Anda. Sebagai pelanggan, itu bagus karena Anda dapat menemukan apa yang dekat, dan implikasi bisnisnya jelas.

Membangun "pencari toko" sebenarnya adalah tugas yang menantang. Dalam tutorial ini, kami akan membahas dasar-dasar cara bekerja dengan data geospasial di Node.js dan Redis dan membangun pencari toko yang belum sempurna.

Kami akan menggunakan perintah 'geo' dari Redis. Perintah-perintah ini ditambahkan dalam versi 3.2, jadi Anda harus menginstalnya di mesin pengembangan Anda. Mari lakukan pemeriksaan singkat — aktifkan redis-cli dan ketik GEOADD. Anda seharusnya melihat pesan kesalahan yang terlihat seperti ini:

Meskipun ada pesan kesalahan, itu pertanda baik — ini menunjukkan bahwa Anda memiliki perintah GEOADD. Jika Anda menjalankan perintah dan Anda mendapatkan kesalahan berikut:

Anda harus mengunduh, membangun, dan menginstal versi Redis yang mendukung perintah geo sebelum Anda melangkah lebih jauh.

Setelah mendapat server Redis yang didukung, mari ikuti tur melalui perintah geo. Redis memiliki enam perintah yang secara langsung terlibat dengan pengindeksan geospasial: GEOADD, GEOHASH, GEOPOS, GEODIST, GEORADIUS, dan GEORADIUSBYMEMBER.

Mari mulai dengan GEOADD. Perintah ini, seperti yang Anda bayangkan, menambahkan item geospasial. Ini memiliki empat argumen yang diperlukan: kunci, bujur, garis lintang, dan anggota. Kuncinya adalah seperti pengelompokan dan merepresentasikan satu nilai di ruang kunci. Bujur dan garis lintang jelas koordinat sebagai pelampung; perhatikan urutan nilai-nilai ini, karena kemungkinannya terbalik dari apa yang biasa Anda lihat. Terakhir, ‘anggota’ adalah bagaimana Anda akan mengidentifikasi suatu lokasi. Dalam redis-cli, mari jalankan perintah berikut:

Ini adalah cara panjang untuk menambahkan beberapa entri, tetapi bagus untuk melihat polanya. Jika Anda ingin mempersingkat proses ini, Anda dapat mencapai hal yang sama dengan mengulangi garis bujur, garis lintang, dan anggota untuk setiap tempat tambahan sebagai argumen yang lebih banyak. Ini adalah contoh representasi singkat dari dua item terakhir:

Secara internal, item geo ini sebenarnya bukan sesuatu yang istimewa — mereka disimpan oleh Redis sebagai zset, atau kumpulan yang diurutkan. Untuk menunjukkan ini, mari jalankan beberapa perintah lagi di va-universities utama:

Ini, mengembalikan zset, sama seperti set yang disortir lainnya. Sekarang, apa yang terjadi jika kita berusaha mendapatkan kembali semua nilai dan memasukkan skor?

Ini mengembalikan sebagian besar dari anggota yang dimasukkan di atas, dengan angka yang sangat besar — ​​sebuah bilangan bulat 52-bit. Bilangan bulat sebenarnya adalah representasi geohash, struktur kecil pintar yang dapat mewakili tempat mana pun di dunia. Kami akan menyelam lebih dalam di kemudian hari dan tidak akan benar-benar berinteraksi dengan data geospasial dengan cara ini, tetapi itu selalu baik untuk mengetahui bagaimana data Anda disimpan.

Sekarang kita memiliki beberapa data untuk dimainkan, mari kita lihat pada perintah GEODIST. Dengan perintah ini, Anda dapat menentukan jarak antara dua titik yang sebelumnya Anda masukkan di bawah kunci yang sama. Jadi, mari kita cari jarak antara anggota virginia-tech dan christopher-newport-university:

Ini harus menghasilkan 349054.2554687438, atau jarak antara dua tempat dalam meter. Anda juga dapat memberikan argumen ketiga sebagai satuan mi (mil), km (kilometer), ft (feet), atau m (meter, default). Mari dapatkan jarak dalam mil:

Yang harus menanggapi dengan '216.89279795987412.'

Sebelum melangkah lebih jauh, mari kita bahas tentang mengapa menghitung jarak antara dua titik geospasial bukan hanya perhitungan geometrik yang lugas. Bumi bulat (atau hampir), jadi saat Anda menjauh dari khatulistiwa, jarak antara garis bujur mulai menyatu dan mereka “bertemu” di kutub. Jadi, untuk menghitung jarak, Anda perlu memperhitungkan globe.

Untungnya, Redis melindungi kita dari matematika ini (jika Anda tertarik, ada contoh implementasi JavaScript murni). Satu catatan, Redis membuat asumsi bahwa bumi adalah bola sempurna (rumus Haversine), dan itu dapat memperkenalkan kesalahan hingga 0,5%, yang cukup baik untuk sebagian besar aplikasi, terutama untuk sesuatu seperti pencari toko.

Seringkali kami ingin semua poin dalam radius tertentu dari suatu lokasi, bukan hanya jarak antara dua titik. Kita bisa melakukan ini dengan perintah GEORADIUS. Perintah GEORADIUS mengharapkan, paling tidak, kunci, garis bujur, garis lintang, jarak, dan unit. Jadi, mari temukan semua universitas dalam kumpulan data dalam radius 100 mil dari titik ini.

Yang mengembalikan:

GEORADIUS memiliki beberapa opsi. Katakanlah kami ingin mendapatkan jarak antara titik yang ditentukan dan semua lokasi. Kita bisa melakukan ini dengan menambahkan argumen WITHDIST di bagian akhir:

Ini mengembalikan balasan massal dengan anggota lokasi dan jarak (dalam unit yang ditentukan):

Argumen opsional lainnya adalah WITHCOORD, yang, seperti sudah Anda duga, memberi Anda kembali koordinat garis bujur dan lintang. Anda dapat mencampur ini dengan argumen WITHDIST juga. Mari kita coba ini:

Set hasil menjadi sedikit lebih rumit:

Perhatikan bahwa jarak datang sebelum koordinat, meskipun urutan terbalik dalam argumen kami. Redis tidak peduli urutan mana Anda menentukan argumen WITH*, tetapi akan mengembalikan jarak sebelum koordinat. Ada satu lagi dengan argumen (WITHHASH), tetapi kami akan membahasnya di bagian selanjutnya — ketahuilah bahwa itu akan menjadi yang terakhir dalam respons Anda.

Singkatnya kalkulasi di sini — jika Anda memikirkan matematika yang kami bahas sebelumnya tentang cara kerja GEODIST, mari pikirkan radius. Karena jari-jari adalah lingkaran, kita harus berpikir tentang lingkaran yang diletakkan di atas bola, yang sangat berbeda dari lingkaran sederhana yang diterapkan di atas bidang datar. Sekali lagi, Redis melakukan semua perhitungan ini untuk kami (untungnya).

Sekarang, mari kita bahas perintah terkait ke GEORADIUS, GEORADIUSBYMEMBER. GEORADIUSBYMEMBER bekerja persis sama dengan GEORADIUS, tetapi alih-alih menetapkan garis bujur dan garis lintang dalam argumen, Anda dapat menentukan anggota yang sudah ada dalam kunci Anda. Jadi ini, misalnya, akan mengembalikan semua anggota dalam jarak 100 mil dari anggota university-of-virginia.

Anda dapat menggunakan unit yang sama dan WITH* argumen dan unit di GEORADIUSBYMEMBER seperti yang Anda bisa pada GEORADIUS.

Sebelumnya, ketika kami menjalankan ZRANGE pada kunci kami, Anda mungkin bertanya-tanya bagaimana cara mengembalikan koordinat dari posisi yang Anda tambahkan dengan GEOADD — kita dapat mencapai ini dengan perintah GEOPOS. Dengan menyediakan kunci dan anggota, kita bisa mendapatkan kembali koordinatnya:

Yang seharusnya menghasilkan hasil:

Jika Anda melihat kembali ketika kami menambahkan nilai untuk university-of-virginia, jumlahnya sedikit berbeda, meskipun mereka membulatkan ke jumlah yang sama. Ini karena Redis menyimpan koordinat dalam format geohash. Sekali lagi, ini sangat dekat dan cukup baik untuk sebagian besar aplikasi-dalam contoh di atas, perbedaan jarak yang sebenarnya antara input dan output GEOPOS adalah 5,5 inci / 14 cm.

Ini membawa kita ke perintah Redis GEO terakhir kami: GEOHASH. Ini akan mengembalikan nilai geohash yang digunakan untuk menahan koordinat. Disebutkan sebelumnya, ini adalah sistem pintar yang didasarkan pada grid dan dapat direpresentasikan dalam berbagai cara — Redis menggunakan integer 52-bit, tetapi representasi yang lebih umum dilihat adalah string basis-32. Menggunakan perintah GEOHASH dengan kunci dan anggota, Redis akan mengembalikan string base-32 yang mewakili lokasi ini. Jika kita jalankan perintah:

Anda akan mendapatkan kembali:

Ini adalah representasi string base-32 geohash. String Geohash memiliki properti yang rapi sehingga jika Anda menghapus karakter dari kanan string, Anda semakin mengurangi ketepatan koordinat. Ini dapat diilustrasikan dengan situs web geohash — lihat tautan ini dan lihat bagaimana koordinat dan peta menjauh dari lokasi asli:

Ada satu fungsi lagi yang harus kita bahas, dan jika Anda sudah akrab dengan kumpulan Redis yang sudah Anda ketahui. Karena data geospasial Anda benar-benar disimpan dalam suatu perubahan, kita dapat menghapus item dengan ZREM:

Server Pencari Toko

Sekarang bahwa kita memiliki dasar-dasar untuk menggunakan perintah Redis GEO, mari kita membangun berbasis Node.js simpan server pencari sebagai contoh. Kami akan menggunakan data dari atas, jadi saya rasa ini secara teknis adalah pencari universitas daripada pencari toko, tetapi konsepnya identik. Sebelum memulai, pastikan Anda memiliki Node.js dan npm yang diinstal. Buatlah direktori untuk proyek Anda dan beralihlah ke direktori tersebut di baris perintah Anda. Pada baris perintah, ketik:

Ini akan membuat file package.json Anda dengan mengajukan beberapa pertanyaan. Setelah Anda menginisialisasi proyek Anda, kami akan memasang empat modul. Sekali lagi, dari baris perintah, jalankan empat perintah berikut:

Modul pertama adalah Express.js, modul server web. Untuk pergi bersama dengan server, kami juga perlu memasang sistem templating. Untuk proyek ini kami akan menggunakan pug (secara resmi dikenal sebagai Jade). Pug terintegrasi dengan baik dengan Express dan akan memungkinkan kita untuk membuat template halaman dasar hanya dalam beberapa baris. Kami juga menginstal node_redis, yang mengelola koneksi antara Node.js dan server Redis. Terakhir, kita memerlukan modul lain untuk menangani menafsirkan nilai-nilai HTTP POST: body-parser.

Untuk langkah pertama kami, kami hanya akan berdiri di server sampai pada titik yang dapat menerima permintaan HTTP dan mengisi template dengan nilai.

Server ini hanya akan berhasil melayani halaman tingkat atas ('/') dan hanya jika klien HTTP (a.k.a. browser) dengan metode GET atau POST.

Kita akan membutuhkan kerangka tulang-kosong — cukup hanya untuk bisa menunjukkan judul, formulir, dan (nanti) menunjukkan hasilnya. Pug adalah bahasa template yang sangat singkat dengan spasi yang relevan. Jadi, dengan lekukan tag bersarang, kata pertama dari baris setelah indentasi adalah tag (dan tag penutup disimpulkan oleh parser) dan kami menginterpolasi nilai dengan #{}. Ini membutuhkan waktu untuk terbiasa, tetapi Anda dapat membuat banyak HTML dengan karakter minimal — lihat situs web pug untuk mempelajari lebih lanjut. Catatan pada saat artikel ini, situs web resmi Pug belum diperbarui. Inilah tiket resmi GitHub terkait masalah tersebut.

Kami dapat mencoba pencari toko kami dengan memulai server pada baris perintah:

Kemudian arahkan browser Anda ke http://localhost: 3000/.

Anda akan melihat halaman polos tanpa distorsi dengan header besar yang bertuliskan 'University Finder' dan formulir dengan beberapa kotak teks. Karena permintaan halaman normal oleh browser adalah permintaan GET, halaman ini sedang dibuat oleh fungsi dalam argumen untuk app.get.

Basic form screenshot

Jika Anda memasukkan nilai ke dalam buku teks Lintang dan Bujur dan klik 'temukan', Anda akan melihat bahwa hasil tersebut dirender dan ditampilkan pada baris yang bertulisan 'Menampilkan Hasil untuk ...' Pada titik ini, Anda tidak akan memiliki hasil apa pun, karena kami belum benar-benar mengintegrasikan Redis.

Form with values after click screenshot

Mengintegrasikan Redis

Untuk mengintegrasikan Redis, pertama-tama kita harus melakukan sedikit penyiapan. Dalam deklarasi variabel, sertakan baik modul dan variabel (yang belum terdefinisi) untuk klien.

Setelah deklarasi variabel, kita harus membuat koneksi ke Redis. Dalam contoh kami, kami akan menganggap koneksi localhost di port default dan tanpa otentikasi (di lingkungan produksi, pastikan untuk melindungi server Redis Anda).

Fitur yang rapi dari node_redis adalah bahwa klien akan mengantri perintah ketika koneksi sedang dibuat, jadi tidak perlu khawatir tentang menunggu untuk membuat koneksi dengan server Redis.

Setelah instance node kami memiliki klien Redis yang dapat menerima koneksi, mari kita bekerja di pusat pencari toko kami. Kami akan mengambil lintang dan bujur pengguna dan menerapkannya ke perintah GEORADIUS. Contoh kami menggunakan radius 100 mil. Kami juga ingin mendapatkan jarak dan koordinat hasil tersebut.

Dalam callback, kami menangani semua kesalahan, jika ada. Jika tidak ditemukan kesalahan, maka petakan hasilnya agar lebih bermakna dan lebih mudah diintegrasikan ke dalam template. Hasil tersebut kemudian dimasukkan ke dalam template.

Dalam template, kita perlu menangani hasil yang ditetapkan. Pug memiliki iterasi yang mulus atas array (dengan sintaks hampir verbal). Ini adalah masalah menarik nilai-nilai itu untuk satu hasil; template akan menangani yang lainnya.

Setelah Anda mendapatkan template final dan kode node di tempatnya, jalankan kembali server app.js Anda dan arahkan browser Anda kembali ke http://localhost: 3000/.

Jika Anda memasukkan garis lintang 38.904722 dan garis bujur -77.016389 (koordinat untuk Washington, DC, di perbatasan utara Virginia) ke dalam kotak dan klik temukan, Anda akan mendapatkan tiga hasil. Jika Anda mengubah nilai ke lintang 37.533333 dan garis bujur -77.466667 (Richmond, Virginia, ibukota negara bagian dan di bagian tengah / timur negara bagian), Anda akan melihat sepuluh hasil.

Pada titik ini, Anda memiliki bagian dasar pencari toko, tetapi Anda harus menyesuaikannya agar sesuai dengan proyek Anda sendiri.

  • Sebagian besar pengguna tidak berpikir dalam hal koordinat, jadi Anda harus mempertimbangkan pendekatan yang lebih ramah pengguna seperti:
    1. Menggunakan JavaScript sisi klien untuk mendeteksi lokasi menggunakan Geolocation API
    2. Menggunakan layanan geolocator berbasis IP
    3. Minta pengguna untuk kode pos atau alamat dan gunakan layanan geocoding yang mengubah keduanya menjadi koordinat. Banyak layanan geocoding yang berbeda ada di pasar, jadi pilih salah satu yang berfungsi dengan baik untuk area target Anda.

  • Skrip ini tidak melakukan validasi form. Jika Anda meninggalkan kotak masukan garis lintang dan garis bujur, Anda harus memastikan bahwa Anda memvalidasi data dan menghindari pesan kesalahan.

  • Perluas kunci lokasi menjadi informasi yang lebih berguna. Jika Anda menggunakan Redis untuk menyimpan lebih banyak informasi tentang setiap lokasi, pertimbangkan menyimpan informasi tersebut dalam hash dengan kunci yang cocok dengan anggota Anda yang dikembalikan dari GEORADIUS. Anda harus membuat call(s) tambahan ke Redis.

  • Integrasi lebih dekat dengan layanan pemetaan seperti Google Maps, OpenStreetMap, atau Bing Maps untuk menyediakan peta dan petunjuk yang tersemat.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.