Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
23 Apr 2021 · 5 mnt baca ·Artikel 97 / 119
Go

Membuat Distibuted Search Engine Sederhana Menggunakan Worker Pool Pada Golang

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Pendahuluan

Kamu tahu google adalah tempat kita mencari beberapa kata kunci yang dapat menghasilkan berbagai jutaan informasi yang kita dapat hanya dengan mengetik beberapa kata kunci dan dalam waktu kurang dari 1 detik kita sudah bisa mendapatkan berbagai informasi terkait kata kunci yang kita cari. Nah ini adalah contoh miniatur atau search engine versi sederhana bagaimana kita bisa mengimplementasikan worker pool menjadi suatu engine yang berguna untuk pencarian.

Kamu sudah memahami bagaimana cara kerja Worker Pool? Jika belum tahu atau sudah tahu tapi ingin memperdalam lagi bisa baca-baca terlebih dahulu di artikel sebelumnya yang pernah Santekno bahas di cara implementasi concurrency worker pool golang .

Persiapan Data Dasar

Sebelum kita membuat program pencarian, kita harus siapkan terlebih dahulu data yang akan dicari. Santekno disini akan memberikan sampel data yang paling sederhana agar mudah untuk dicerna oleh teman-teman semuanya.

Kita akan membuat data berupa informasi User yang terdapat atribut nama dan email. Nama dan email ini yang akan kita dijadikan data yang akan dicari.

go
 1type User struct {
 2	Name  string
 3	Email string
 4}
 5
 6var Database = []User{
 7	{Name: "ihsan arif", Email: "ihsan.arif@example.com"},
 8	{Name: "ihsan nugraha", Email: "ihsa@example.com"},
 9	{Name: "arif susanto", Email: "arif.susanto@example.com"},
10	{Name: "ines nur", Email: "ines.nur@example.com"},
11	{Name: "inez hendriani", Email: "inez.hendriani@example.com"},
12	{Name: "deni siahaan", Email: "deni.siahaan@example.com"},
13	{Name: "sumarno treggono", Email: "sumarno.trenggono@example.com"},
14	{Name: "nida fauziah", Email: "nida.fauziah@example.com"},
15	{Name: "nurul kamilah", Email: "nurul.kamilah@example.com"},
16	{Name: "muhammad rafi", Email: "muhammad.rafi@example.com"},
17	{Name: "irfan maulana", Email: "irfan.maulana@example.com"},
18	{Name: "irsyad aprilianto", Email: "irsyad.aprilianto@example.com"},
19	{Name: "iqbal fauzi", Email: "iqbal.fauzi@example.com"},
20	{Name: "rani zahroh", Email: "rani.zahroh@example.com"},
21	{Name: "ajeng syifa", Email: "ajeng.syifa@example.com"},
22	{Name: "aldi arikandi", Email: "aldi.arikandi@example.com"},
23	{Name: "firman syah", Email: "firman.syah@example.com"},
24	{Name: "irwan setiawan", Email: "irwan.setiawan@example.com"},
25}

Inisialisasi Worker Pool

Kenapa kita menggunakan worker pool? Jawaban sederhananya yaitu agar proses pencarian berdasarkan kata kunci ke dalam database (sumber data) lebih cepat dan dibagi-bagi. Bisa kita lihat dibawah ini inisialisasi Worker struct menjadi object yang nanti kita gunakan untuk pencarian di fungsi main. Jika masih bingung lihat saja dulu potongan program untuk inisialisasi Woerker-nya.

go
1type Worker struct {
2	Users []User
3	ch    chan *User
4	Name  string
5}
6
7func NewWorker(users []User, ch chan *User, name string) *Worker {
8	return &Worker{Users: users, ch: ch, Name: name}
9}

Fungsi Pencarian

Fungsi utama dari worker akan kita buat dibawah objek worker agar saat pencarian lebih mudah.

go
1func (w *Worker) Find(email string) *User {
2	for i := range w.Users {
3		user := &w.Users[i]
4		if strings.Contains(user.Email, email) {
5			w.ch <- user
6		}
7	}
8	return nil
9}

Fungi Main Program

Fungsi ini menjalankan proses inisialisasi worker, pengambilan data dan membaca input untuk jadi kata kunci yang akan dicari pada basis data.

go
 1func main() {
 2    // untuk mengambil argumen masukan
 3	email := os.Args[1]
 4    // inisialisasi channel objek user
 5	ch := make(chan *User)
 6    // inisialisasi worker pool sebanyak 3 pool 
 7	for i := 0; i < 3; i++ {
 8		go NewWorker(Database[(len(Database)/3*i):len(Database)/3*(i+1)], ch, fmt.Sprintf("#%s", i)).Find(email)
 9	}
10
11    // mencetak hasil dari pencarian
12	select {
13	case user := <-ch:
14		log.Printf("the email %s is owned by %s", email, user.Email)
15	case <-time.After(100 * time.Millisecond):
16		log.Printf("the email %s was not found", email)
17	}
18}

Output Program

bash
1-> go run content/post/main.go ihsan.arif
22021/05/10 19:38:00 the email ihsan.arif is owned by ihsan.arif@example.com
3-> go run content/post/main.go ines      
42021/05/10 19:38:04 the email ines is owned by ines.nur@example.com
5-> go run content/post/main.go unyil
62021/05/10 19:40:49 the email unyil was not found

Program keseluruhan

distributed-search-engine.go
 1package main
 2
 3import (
 4	"fmt"
 5	"log"
 6	"os"
 7	"strings"
 8	"time"
 9)
10
11type User struct {
12	Name  string
13	Email string
14}
15
16var Database = []User{
17	{Name: "ihsan arif", Email: "ihsan.arif@example.com"},
18	{Name: "ihsan nugraha", Email: "ihsa@example.com"},
19	{Name: "arif susanto", Email: "arif.susanto@example.com"},
20	{Name: "ines nur", Email: "ines.nur@example.com"},
21	{Name: "inez hendriani", Email: "inez.hendriani@example.com"},
22	{Name: "deni siahaan", Email: "deni.siahaan@example.com"},
23	{Name: "sumarno treggono", Email: "sumarno.trenggono@example.com"},
24	{Name: "nida fauziah", Email: "nida.fauziah@example.com"},
25	{Name: "nurul kamilah", Email: "nurul.kamilah@example.com"},
26	{Name: "muhammad rafi", Email: "muhammad.rafi@example.com"},
27	{Name: "irfan maulana", Email: "irfan.maulana@example.com"},
28	{Name: "irsyad aprilianto", Email: "irsyad.aprilianto@example.com"},
29	{Name: "iqbal fauzi", Email: "iqbal.fauzi@example.com"},
30	{Name: "rani zahroh", Email: "rani.zahroh@example.com"},
31	{Name: "ajeng syifa", Email: "ajeng.syifa@example.com"},
32	{Name: "aldi arikandi", Email: "aldi.arikandi@example.com"},
33	{Name: "firman syah", Email: "firman.syah@example.com"},
34	{Name: "irwan setiawan", Email: "irwan.setiawan@example.com"},
35}
36
37type Worker struct {
38	Users []User
39	ch    chan *User
40	Name  string
41}
42
43func NewWorker(users []User, ch chan *User, name string) *Worker {
44	return &Worker{Users: users, ch: ch, Name: name}
45}
46
47func (w *Worker) Find(email string) *User {
48	for i := range w.Users {
49		user := &w.Users[i]
50		if strings.Contains(user.Email, email) {
51			w.ch <- user
52		}
53	}
54	return nil
55}
56
57func main() {
58	email := os.Args[1]
59
60	ch := make(chan *User)
61
62	for i := 0; i < 2; i++ {
63		go NewWorker(Database[(len(Database)/3*i):len(Database)/3*(i+1)], ch, fmt.Sprintf("#%s", i)).Find(email)
64	}
65
66	select {
67	case user := <-ch:
68		log.Printf("the email %s is owned by %s", email, user.Email)
69	case <-time.After(100 * time.Millisecond):
70		log.Printf("the email %s was not found", email)
71	}
72}

Artikel Terkait

💬 Komentar