cari
Rumahpembangunan bahagian belakangGolangBleve: Bagaimana untuk membina enjin carian pantas roket?

Bleve: How to build a rocket-fast search engine?

Go/Golang ialah salah satu bahasa kegemaran saya; Saya suka minimalisme dan betapa bersihnya, ia sangat padat dari segi sintaks dan berusaha keras untuk memastikan perkara mudah (saya peminat tegar prinsip KISS).

Salah satu cabaran utama yang saya hadapi sejak kebelakangan ini ialah membina enjin carian yang pantas. Pasti ada pilihan seperti SOLR dan ElasticSearch; kedua-duanya berfungsi dengan baik dan sangat berskala, walau bagaimanapun, saya perlu memudahkan carian, dengan menjadikannya lebih pantas dan lebih mudah untuk digunakan dengan sedikit atau tiada kebergantungan.

Saya perlu mengoptimumkan cukup untuk saya memulangkan hasil dengan cepat supaya keputusan itu boleh ditarafkan semula. Walaupun C/Rust mungkin sesuai untuk ini, saya menghargai kelajuan pembangunan dan produktiviti. Golang adalah yang terbaik dari kedua-dua dunia saya rasa.

Dalam artikel ini, saya akan melihat contoh mudah bagaimana anda boleh membina enjin carian anda sendiri menggunakan Go, anda akan terkejut: ia tidaklah sesulit yang anda fikirkan.

Golang: Python pada steroid

Saya tidak tahu mengapa, tetapi Golang berasa seperti Python dalam satu cara. Sintaksnya sangat mudah untuk difahami, mungkin kerana kekurangan koma bertitik dan tanda kurung di mana-mana atau kekurangan kenyataan cuba-tangkap yang jelek. Mungkin ia adalah pemformat Go yang hebat, saya tidak tahu.

Apa pun, memandangkan Golang menjana satu binari serba lengkap, ia sangat mudah untuk digunakan ke mana-mana pelayan pengeluaran. Anda hanya "pergi membina" dan tukar keluar yang boleh laku.

Itulah yang saya perlukan.

Adakah anda Bleve?

Tidak, itu bukan kesilapan menaip ?. Bleve ialah perpustakaan carian yang berkuasa, mudah digunakan dan sangat fleksibel untuk Golang.

Semasa sebagai pembangun Go, anda biasanya mengelakkan pakej pihak ketiga seperti wabak; kadang-kadang masuk akal untuk menggunakan pakej pihak ke-3. Bleve adalah pantas, direka bentuk dengan baik dan memberikan nilai yang mencukupi untuk membenarkan penggunaannya.

Selain itu, inilah sebab mengapa saya "Bleve":

  • Sendiri, salah satu kelebihan besar Golang ialah binari tunggal, jadi saya ingin mengekalkan rasa itu dan tidak memerlukan DB atau perkhidmatan luaran untuk menyimpan dan menanyakan dokumen. Bleve berjalan dalam ingatan dan menulis pada cakera yang serupa dengan Sqlite.

  • Mudah dipanjangkan. Memandangkan ia hanya kod Go, saya boleh mengubah suai perpustakaan atau memanjangkannya dengan mudah dalam pangkalan kod saya mengikut keperluan.

  • Pantas: Hasil carian merentas 10 juta dokumen mengambil masa hanya 50-100ms, ini termasuk penapisan.

  • Faceting: anda tidak boleh membina enjin carian moden tanpa beberapa tahap sokongan faceting. Bleve mempunyai sokongan penuh untuk jenis faset biasa: seperti julat atau kiraan kategori mudah.

  • Pengindeksan pantas: Bleve agak perlahan daripada SOLR. SOLR boleh mengindeks 10 juta dokumen dalam masa 30 minit, manakala Bleve mengambil masa lebih sejam, bagaimanapun, sejam atau lebih masih cukup baik dan cukup pantas untuk keperluan saya.

  • Hasil kualiti yang baik. Bleve berfungsi dengan baik dengan hasil kata kunci tetapi beberapa carian jenis semantik juga berfungsi dengan baik dalam Bleve.

  • Permulaan pantas: Jika anda perlu memulakan semula atau menggunakan kemas kini, hanya milisaat diperlukan untuk memulakan semula Bleve. Tiada penyekatan bacaan untuk membina semula indeks dalam ingatan, jadi carian indeks boleh dilakukan tanpa gangguan hanya beberapa milisaat selepas dimulakan semula.

Sediakan indeks?

Dalam Bleve, "Indeks" boleh dianggap sebagai jadual pangkalan data atau koleksi (NoSQL). Tidak seperti jadual SQL biasa, anda tidak perlu menentukan setiap lajur tunggal, pada asasnya anda boleh lari dengan skema lalai untuk kebanyakan kes penggunaan.

Untuk memulakan indeks Bleve, anda boleh melakukan perkara berikut:

mappings := bleve.NewIndexMapping()
index, err = bleve.NewUsing("/some/path/index.bleve", mappings, "scorch", "scorch", nil)
if err != nil {
    log.Fatal(err)
}

Bleve menyokong beberapa jenis indeks yang berbeza, tetapi saya dapati setelah banyak mengutak-atik bahawa jenis indeks "hangus" memberikan anda prestasi terbaik. Jika anda tidak lulus dalam 3 hujah terakhir, Bleve hanya akan lalai kepada BoltDB.

Menambah dokumen

Menambah dokumen pada Bleve adalah mudah. Anda pada asasnya boleh menyimpan sebarang jenis struct dalam indeks:

type Book struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Genre string `json:"genre"`
}

b := Book{
    ID:    1234,
    Name:  "Some creative title",
    Genre: "Young Adult",
}
idStr := fmt.Sprintf("%d", b.ID)
// index(string, interface{})
index.index(idStr, b)

Jika anda mengindeks sejumlah besar dokumen, lebih baik menggunakan kumpulan:

// You would also want to check if the batch exists already
// - so that you don't recreate it.
batch := index.NewBatch()
if batch.Size() >= 1000 {
    err := index.Batch(batch)
    if err != nil {
        // failed, try again or log etc...
    }
    batch = index.NewBatch()
} else {
    batch.index(idStr, b)
}

Seperti yang anda akan perhatikan, tugas yang rumit seperti menyusun rekod dan menulisnya pada indeks dipermudahkan menggunakan "index.NewBatch" yang mencipta bekas untuk mengindeks dokumen buat sementara waktu.

Selepas itu anda hanya semak saiz semasa anda melingkari dan siram indeks sebaik sahaja anda mencapai had saiz kelompok.

Mencari indeks

Bleve mendedahkan berbilang penghurai pertanyaan carian berbeza yang boleh anda pilih bergantung pada keperluan carian anda. Untuk memastikan artikel ini pendek dan manis, saya hanya akan menggunakan penghurai rentetan pertanyaan standard.

searchParser := bleve.NewQueryStringQuery("chicken reciepe books")
maxPerPage := 50
ofsset := 0
searchRequest := bleve.NewSearchRequestOptions(searchParser, maxPerPage, offset, false)
// By default bleve returns just the ID, here we specify
// - all the other fields we would like to return.
searchRequest.Fields = []string{"id", "name", "genre"}
searchResults, err := index.Search(searchResult)

Dengan hanya beberapa baris ini, anda kini mempunyai enjin carian yang berkuasa yang memberikan hasil yang baik dengan memori dan jejak sumber yang rendah.

Berikut ialah perwakilan JSON bagi hasil carian, "hits" akan mengandungi dokumen yang sepadan:

{
    "status": {
        "total": 5,
        "failed": 0,
        "successful": 5
    },
    "request": {},
    "hits": [],
    "total_hits": 19749,
    "max_score": 2.221337297308545,
    "took": 99039137,
    "facets": null
}

Faceting

Seperti yang dinyatakan sebelum ini, Bleve menyediakan sokongan aspek penuh di luar kotak tanpa perlu menyediakannya dalam skema anda. Untuk Facet pada buku "Genre" misalnya, anda boleh melakukan perkara berikut:

//... build searchRequest -- see previous section.
// Add facets
genreFacet := bleve.NewFacetRequest("genre", 50)
searchRequest.AddFacet("genre", genreFacet)
searchResults, err := index.Search(searchResult)

Kami melanjutkan Permintaan carian kami dari awal dengan hanya 2 baris kod. "NewFacetRequest" mengambil 2 argumen:

  • Medan: medan dalam indeks kami kepada faset pada (rentetan).

  • Saiz: bilangan entri untuk dikira (integer). Oleh itu dalam contoh kami, ia hanya akan mengira 50 genre pertama.

Yang di atas kini akan mengisi "faset" dalam hasil carian kami.

Seterusnya, kami hanya menambah aspek kami pada permintaan carian. Yang mengambil "nama aspek" dan aspek sebenar. "Nama facet" ialah "kunci" anda akan dapati keputusan ini ditetapkan di bawah dalam hasil carian kami.

Pertanyaan lanjutan dan penapisan

Walaupun penghurai "QueryStringQuery" boleh memberikan anda sedikit perbatuan; kadangkala anda memerlukan pertanyaan yang lebih kompleks seperti "seseorang mesti sepadan" di mana anda ingin memadankan istilah carian dengan beberapa medan dan mengembalikan hasil asalkan sekurang-kurangnya satu medan sepadan.

Anda boleh menggunakan jenis pertanyaan "Disjunction" dan "Conjunction" untuk mencapai ini.

  • Pertanyaan Konjungsi: Pada asasnya, ia membolehkan anda merangkaikan berbilang pertanyaan bersama-sama untuk membentuk satu pertanyaan gergasi. Semua pertanyaan kanak-kanak mesti sepadan dengan sekurang-kurangnya satu dokumen.

  • Pertanyaan Disjungsi: Ini akan membolehkan anda melakukan pertanyaan "satu mesti sepadan" yang dinyatakan di atas. Anda boleh menghantar dalam x jumlah pertanyaan dan menetapkan bilangan pertanyaan kanak-kanak mesti sepadan dengan sekurang-kurangnya satu dokumen.

Contoh Pertanyaan Disjungsi:

mappings := bleve.NewIndexMapping()
index, err = bleve.NewUsing("/some/path/index.bleve", mappings, "scorch", "scorch", nil)
if err != nil {
    log.Fatal(err)
}

Sama seperti cara kami menggunakan "searchParser" sebelum ini, kami kini boleh menghantar "Disjunction Query" ke dalam pembina untuk "searchRequest" kami.

Walaupun tidak betul-betul sama, ini menyerupai SQL berikut:

type Book struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Genre string `json:"genre"`
}

b := Book{
    ID:    1234,
    Name:  "Some creative title",
    Genre: "Young Adult",
}
idStr := fmt.Sprintf("%d", b.ID)
// index(string, interface{})
index.index(idStr, b)

Anda juga boleh melaraskan betapa kaburnya carian anda mahukan dengan menetapkan "query.Fuzziness=[0 atau 1 atau 2]"

Contoh Pertanyaan Kata Hubung:

// You would also want to check if the batch exists already
// - so that you don't recreate it.
batch := index.NewBatch()
if batch.Size() >= 1000 {
    err := index.Batch(batch)
    if err != nil {
        // failed, try again or log etc...
    }
    batch = index.NewBatch()
} else {
    batch.index(idStr, b)
}

Anda akan perasan sintaksnya sangat serupa, pada asasnya anda hanya boleh menggunakan pertanyaan "Konjungsi" dan "Disjungsi" secara bergantian.

Ini akan kelihatan serupa dengan yang berikut dalam SQL:

searchParser := bleve.NewQueryStringQuery("chicken reciepe books")
maxPerPage := 50
ofsset := 0
searchRequest := bleve.NewSearchRequestOptions(searchParser, maxPerPage, offset, false)
// By default bleve returns just the ID, here we specify
// - all the other fields we would like to return.
searchRequest.Fields = []string{"id", "name", "genre"}
searchResults, err := index.Search(searchResult)

Ringkasnya; gunakan "Pertanyaan Konjungsi" apabila anda mahu semua pertanyaan kanak-kanak sepadan dengan sekurang-kurangnya satu dokumen dan "Pertanyaan Disjungsi" apabila anda mahu memadankan sekurang-kurangnya satu pertanyaan kanak-kanak tetapi tidak semestinya semua pertanyaan kanak-kanak.

Sharding

Jika anda menghadapi masalah kelajuan, Bleve juga memungkinkan untuk mengedarkan data anda merentasi berbilang serpihan indeks dan kemudian menanyakan serpihan tersebut dalam satu permintaan, contohnya:

{
    "status": {
        "total": 5,
        "failed": 0,
        "successful": 5
    },
    "request": {},
    "hits": [],
    "total_hits": 19749,
    "max_score": 2.221337297308545,
    "took": 99039137,
    "facets": null
}

Sharding boleh menjadi agak rumit, tetapi seperti yang anda lihat di atas, Bleve menghilangkan banyak kesakitan, kerana ia secara automatik "menggabungkan" semua indeks dan carian merentasinya, dan kemudian mengembalikan hasil dalam satu set keputusan sama seperti anda mencari satu indeks.

Saya telah menggunakan sharding untuk mencari 100 shards. Keseluruhan proses carian selesai dalam purata 100-200 milisaat sahaja.

Anda boleh mencipta serpihan seperti berikut:

//... build searchRequest -- see previous section.
// Add facets
genreFacet := bleve.NewFacetRequest("genre", 50)
searchRequest.AddFacet("genre", genreFacet)
searchResults, err := index.Search(searchResult)

Cuma pastikan anda membuat ID unik untuk setiap dokumen atau mempunyai semacam cara yang boleh diramal untuk menambah dan mengemas kini dokumen tanpa mengacaukan indeks.

Cara mudah untuk melakukan ini ialah dengan menyimpan awalan yang mengandungi nama serpihan dalam DB sumber anda, atau dari mana-mana sahaja anda mendapatkan dokumen itu. Supaya setiap kali anda cuba memasukkan atau mengemas kini, anda mencari "awalan" yang akan memberitahu anda bahagian mana yang hendak dipanggil ".index".

Bercakap tentang pengemaskinian, hanya memanggil "index.index(idstr, struct)" akan mengemas kini dokumen sedia ada.

Kesimpulan

Hanya menggunakan teknik carian asas ini di atas dan meletakkannya di belakang GIN atau pelayan HTTP Go standard, anda boleh membina API carian yang cukup berkuasa dan menyediakan berjuta-juta permintaan tanpa perlu melancarkan infrastruktur yang kompleks.

Satu kaveat; Bleve tidak memenuhi keperluan replikasi, bagaimanapun, kerana anda boleh membungkusnya dalam API. Hanya ada tugas cron yang membaca daripada sumber anda dan "meletupkan" kemas kini kepada semua pelayan Bleve anda menggunakan goroutine.

Sebagai alternatif, anda hanya boleh mengunci tulisan ke cakera selama beberapa saat dan kemudian hanya "rsync" data merentas ke indeks hamba, walaupun saya tidak menasihati berbuat demikian kerana anda mungkin juga perlu memulakan semula binari pergi setiap kali .

Atas ialah kandungan terperinci Bleve: Bagaimana untuk membina enjin carian pantas roket?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Pergi pengendalian ralat: Amalan dan corak terbaikPergi pengendalian ralat: Amalan dan corak terbaikMay 04, 2025 am 12:19 AM

Dalam pengaturcaraan GO, cara untuk menguruskan kesilapan secara berkesan termasuk: 1) menggunakan nilai ralat dan bukannya pengecualian, 2) menggunakan teknik pembalut ralat, 3) menentukan jenis ralat tersuai, 4) menggunakan semula nilai ralat untuk prestasi, 5) menggunakan panik dan pemulihan dengan berhati-hati, memastikan mesej ralat, 7) Amalan dan corak ini membantu menulis kod yang lebih mantap, boleh dipelihara dan cekap.

Bagaimana anda melaksanakan kesesuaian dalam perjalanan?Bagaimana anda melaksanakan kesesuaian dalam perjalanan?May 04, 2025 am 12:13 AM

Melaksanakan kesesuaian dalam GO boleh dicapai dengan menggunakan goroutin dan saluran. 1) Gunakan goroutin untuk melaksanakan tugas selari, seperti menikmati muzik dan memerhati rakan -rakan pada masa yang sama dalam contoh. 2) Memindahkan data dengan selamat antara goroutin melalui saluran, seperti model pengeluar dan pengguna. 3) Elakkan penggunaan goroutine dan kebuntuan yang berlebihan, dan reka bentuk sistem dengan munasabah untuk mengoptimumkan program serentak.

Membina struktur data serentak di GOMembina struktur data serentak di GOMay 04, 2025 am 12:09 AM

Gooffersmultipleapproachesforbuildingconcurrentdatastructures, termasukmutexes, saluran, andatomicoperations.1) mutexesprovidesimpleThreadsafetybutcancaPanperformanceBottlenecks.2) channelsoferscalabilitybutmayblockiffullorpty.

Membandingkan pengendalian ralat Go ke bahasa pengaturcaraan lainMembandingkan pengendalian ralat Go ke bahasa pengaturcaraan lainMay 04, 2025 am 12:09 AM

Go'serrorhandlingisexplicit, TreatingerRorSasReturnedValuesRatheHanexceptions, unsikepythonandjava.1) Go'sapproachensureSerrorawarenessbutcanleadtoverbosecode.2)

Kod ujian yang bergantung pada fungsi init di GOKod ujian yang bergantung pada fungsi init di GOMay 03, 2025 am 12:20 AM

WhentestingGocodewithinitfunctions,useexplicitsetupfunctionsorseparatetestfilestoavoiddependencyoninitfunctionsideeffects.1)Useexplicitsetupfunctionstocontrolglobalvariableinitialization.2)Createseparatetestfilestobypassinitfunctionsandsetupthetesten

Membandingkan pendekatan pengendalian ralat Go ke bahasa lainMembandingkan pendekatan pengendalian ralat Go ke bahasa lainMay 03, 2025 am 12:20 AM

Go'SerrorHandlingReturnSerrorsArvalues, tidak seperti yang tidak seperti ini) go'SmethodensurexplIciterRorHandling, promMORPORUSustCodeBUtinceangeRningSniSik

Amalan terbaik untuk mereka bentuk antara muka yang berkesan di GOAmalan terbaik untuk mereka bentuk antara muka yang berkesan di GOMay 03, 2025 am 12:18 AM

AneffectiveInterfaceingoisminimal, clear, andpromotesloosecoupling.1) minimizetheinterforflexabilityandeaseofimplementation.2) userInterfacesforabstractionToSwapImplementationswithoutchangingcallingcode.3) Rekabentuk DesignForTabilitybyPrementeMaceStomockDePdePode.3) Rekabentuk

Strategi pengendalian ralat terpusat di manaStrategi pengendalian ralat terpusat di manaMay 03, 2025 am 12:17 AM

Pengendalian ralat berpusat boleh meningkatkan kebolehbacaan dan mengekalkan kod dalam bahasa Go. Kaedah dan kelebihan pelaksanaannya termasuk: 1. 2. Memastikan konsistensi pengendalian kesilapan dengan pengendalian berpusat. 3. Gunakan menangguhkan dan pulih untuk menangkap dan memproses panik untuk meningkatkan ketahanan program.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

SublimeText3 Linux versi baharu

SublimeText3 Linux versi baharu

SublimeText3 Linux versi terkini

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Persekitaran pembangunan bersepadu PHP yang berkuasa

DVWA

DVWA

Damn Vulnerable Web App (DVWA) ialah aplikasi web PHP/MySQL yang sangat terdedah. Matlamat utamanya adalah untuk menjadi bantuan bagi profesional keselamatan untuk menguji kemahiran dan alatan mereka dalam persekitaran undang-undang, untuk membantu pembangun web lebih memahami proses mengamankan aplikasi web, dan untuk membantu guru/pelajar mengajar/belajar dalam persekitaran bilik darjah Aplikasi web keselamatan. Matlamat DVWA adalah untuk mempraktikkan beberapa kelemahan web yang paling biasa melalui antara muka yang mudah dan mudah, dengan pelbagai tahap kesukaran. Sila ambil perhatian bahawa perisian ini

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.