Peringatan
Permata saat ini tidak dipertahankan dan pengembangan ditunda. Jika Anda tertarik untuk mengambil alih, jangan ragu untuk menghubungi saya.
Butuh pencarian teks lengkap yang cepat untuk skrip ruby Anda, tetapi Solr dan Elasticsearch adalah berlebihan? ?
Anda berada di tempat yang tepat. Tantiny adalah perpustakaan pencarian teks lengkap minimalis untuk Ruby berdasarkan tanti v y (alternatif yang luar biasa untuk Apache Lucene yang ditulis dalam karat). Ini bagus untuk kasus-kasus ketika tugas Anda di tangan memerlukan pencarian teks lengkap, tetapi mengkonfigurasi mesin pencari terdistribusi penuh akan membutuhkan waktu lebih dari tugas itu sendiri. Dan bahkan jika Anda sudah menggunakan mesin seperti itu dalam proyek Anda (yang sangat mungkin, sebenarnya), mungkin masih lebih mudah untuk hanya menggunakan Tantiny sebagai gantinya karena tidak seperti Solr dan Elasticsearch, ia tidak memerlukan apa pun untuk bekerja (tidak ada server atau proses yang terpisah atau apa pun), itu murni disematkan. Jadi, ketika Anda menemukan diri Anda dalam situasi saat menggunakan mesin pencari pilihan Anda akan rumit/tidak tahan atau akan memerlukan pengaturan tambahan, Anda selalu dapat kembali ke solusi cepat dan kotor yang tidak fleksibel dan cepat.
Tantiny bukan binding ruby untuk tanttivy, tetapi mencoba untuk menjadi dekat. Filosofi utamanya adalah memberikan akses tingkat rendah ke indeks terbalik Tantivy, tetapi dengan API ruby-esque yang bagus, default yang masuk akal, dan fungsionalitas tambahan yang ditaburkan di atas.
Lihatlah contoh paling mendasar:
index = Tantiny :: Index . new ( "/path/to/index" ) { text :description }
index << { id : 1 , description : "Hello World!" }
index << { id : 2 , description : "What's up?" }
index << { id : 3 , description : "Goodbye World!" }
index . reload
index . search ( "world" ) # 1, 3 Tambahkan baris ini ke gemfile aplikasi Anda:
gem "tantiny"Dan kemudian mengeksekusi:
$ bundle install
Atau instal sendiri sebagai:
$ gem install tantiny
Anda tidak harus menginstal karat di sistem Anda karena Tantiny akan mencoba mengunduh biner yang telah dikompilasi sebelumnya yang di-host pada rilis GitHub selama instalasi. Namun, jika tidak ada biner yang telah dikompilasi sebelumnya ditemukan untuk sistem Anda (yang merupakan kombinasi dari platform, arsitektur, dan versi ruby) Anda perlu menginstal karat terlebih dahulu.
Peringatan
Hanya versi karat hingga 1.77 yang didukung. Lihat masalah ini untuk detail lebih lanjut.
Penting
Tolong, pastikan untuk menentukan versi minor saat menyatakan ketergantungan pada tantiny . API adalah subjek untuk berubah, dan sampai mencapai 1.0.0 benjolan dalam versi minor kemungkinan besar akan menandakan perubahan yang melanggar.
Anda harus menentukan jalur ke tempat indeks akan disimpan dan blok yang mendefinisikan skema:
Tantiny :: Index . new "/tmp/index" do
id :imdb_id
facet :category
string :title
text :description
integer :duration
double :rating
date :release_date
endBerikut adalah deskripsi untuk setiap jenis bidang:
| Jenis | Keterangan |
|---|---|
| pengenal | Menentukan di mana ID dokumen disimpan (default ke :id ). |
| segi | Bidang dengan nilai -nilai seperti /animals/birds (yaitu kategori hierarki). |
| rangkaian | Bidang dengan teks yang tidak tokenized. |
| teks | Bidang dengan teks yang di -tokenized oleh tokenizer yang ditentukan. |
| bilangan bulat | Bidang dengan nilai integer. |
| dobel | Bidang dengan nilai float. |
| tanggal | Bidang dengan jenis DateTime atau sesuatu yang dikonversi menjadi. |
Anda dapat memberi makan indeks segala jenis objek yang memiliki metode yang ditentukan dalam skema Anda, tetapi hash biasa juga berfungsi:
rio_bravo = OpenStruct . new (
imdb_id : "tt0053221" ,
type : '/western/US' ,
title : "Rio Bravo" ,
description : "A small-town sheriff enlists a drunk, a kid and an old man to help him fight off a ruthless cattle baron." ,
duration : 141 ,
rating : 8.0 ,
release_date : Date . parse ( "March 18, 1959" )
)
index << rio_bravo
hanabi = {
imdb_id : "tt0119250" ,
type : "/crime/Japan" ,
title : "Hana-bi" ,
description : "Nishi leaves the police in the face of harrowing personal and professional difficulties. Spiraling into depression, he makes questionable decisions." ,
duration : 103 ,
rating : 7.7 ,
release_date : Date . parse ( "December 1, 1998" )
}
index << hanabi
brother = {
imdb_id : "tt0118767" ,
type : "/crime/Russia" ,
title : "Brother" ,
description : "An ex-soldier with a personal honor code enters the family crime business in St. Petersburg, Russia." ,
duration : 99 ,
rating : 7.9 ,
release_date : Date . parse ( "December 12, 1997" )
}
index << brotherUntuk memperbarui dokumen cukup tambahkan lagi (selama ID sama):
rio_bravo . rating = 10.0
index << rio_bravoAnda juga dapat menghapusnya jika Anda mau:
index . delete ( rio_bravo . imdb_id ) Jika Anda perlu melakukan beberapa operasi penulisan (yaitu lebih dari satu), Anda harus selalu menggunakan transaction :
index . transaction do
index << rio_bravo
index << hanabi
index << brother
end Transaksi mengubah kelompok dan berkomitmen pada indeks dalam sekali jalan. Ini secara dramatis lebih efisien daripada melakukan perubahan ini satu per satu. Faktanya, semua operasi penulisan (yaitu << dan delete ) dibungkus dalam transaksi secara implisit ketika Anda menyebutnya di luar transaksi, jadi memanggil << 10 kali di luar transaksi adalah hal yang sama dengan melakukan 10 transaksi terpisah.
Tantiny yang aman-aman berarti Anda dapat dengan aman membagikan satu instance indeks antar utas. Anda juga dapat menelurkan proses terpisah yang dapat menulis dan membaca dari indeks yang sama. Namun, saat membaca dari indeks harus paralel, menulis tidak . Setiap kali Anda memanggil transaction atau operasi lain yang memodifikasi indeks (yaitu << dan delete ) itu akan mengunci indeks selama durasi operasi atau menunggu proses atau utas lain untuk melepaskan kunci. Satu -satunya pengecualian untuk ini adalah ketika ada proses lain dengan indeks dengan penulis eksklusif berjalan di suatu tempat di mana metode yang memodifikasi indeks akan segera gagal.
Dengan demikian, yang terbaik adalah memiliki satu proses penulis dan banyak proses pembaca jika Anda ingin menghindari pemblokiran panggilan. Cara yang tepat untuk melakukan ini adalah dengan mengatur exclusive_writer ke true saat menginisialisasi indeks:
index = Tantiny :: Index . new ( "/path/to/index" , exclusive_writer : true ) { }Dengan cara ini penulis indeks hanya akan diperoleh sekali yang berarti memori untuk itu dan mengindeks utas hanya akan dialokasikan sekali. Kalau tidak, seorang penulis indeks baru diperoleh setiap kali Anda melakukan operasi penulisan.
Pastikan indeks Anda terkini dengan memuat ulang terlebih dahulu:
index . reloadDan cari (akhirnya!):
index . search ( "a drunk, a kid, and an old man" )Secara default itu akan mengembalikan ID dari 10 dokumen pencocokan terbaik, tetapi Anda dapat menyesuaikannya:
index . search ( "a drunk, a kid, and an old man" , limit : 100 ) Anda mungkin bertanya -tanya, bagaimana tepatnya melakukan pencarian? Nah, perilaku default adalah menggunakan pencarian smart_query (lihat di bawah untuk detailnya) di semua bidang text yang ditentukan dalam skema Anda. Jadi, Anda dapat melewati parameter yang diterima smart_query di sini:
index . search ( "a dlunk, a kib, and an olt mab" , fuzzy_distance : 1 )Namun, Anda dapat menyesuaikannya dengan menyusun kueri Anda sendiri di luar blok bangunan dasar:
popular_movies = index . range_query ( :rating , 8.0 .. 10.0 )
about_sheriffs = index . term_query ( :description , "sheriff" )
crime_movies = index . facet_query ( :cetegory , "/crime" )
long_ass_movies = index . range_query ( :duration , 180 .. 9999 )
something_flashy = index . smart_query ( :description , "bourgeoisie" )
index . search ( ( popular_movies & about_sheriffs ) | ( crime_movies & ! long_ass_movies ) | something_flashy )Saya tahu, rasa aneh! Tapi cukup keren, ya? Lihatlah semua pertanyaan yang tersedia di bawah ini.
| Pertanyaan | Perilaku |
|---|---|
| All_Query | Mengembalikan semua dokumen yang diindeks. |
| kosong_query | Mengembalikan persis apa pun (digunakan secara internal). |
| Term_Query | Dokumen yang berisi istilah yang ditentukan. |
| fuzzy_term_query | Dokumen yang berisi istilah yang ditentukan dalam jarak levenshtein. |
| frase_query | Dokumen yang berisi urutan istilah yang ditentukan. |
| Regex_Query | Dokumen yang berisi istilah yang cocok dengan regex yang ditentukan. |
| awalan_query | Dokumen yang berisi istilah dengan awalan yang ditentukan. |
| range_query | Dokumen yang dengan bidang integer , double atau date dalam kisaran yang ditentukan. |
| facet_query | Dokumen yang termasuk dalam kategori yang ditentukan. |
| Smart_Query | Kombinasi term_query , fuzzy_term_query dan prefix_query . |
Lihatlah file tanda tangan untuk melihat parameter apa yang diterima kueri.
Semua kueri dapat mencari di bidang multuple (kecuali untuk facet_query karena tidak masuk akal di sana).
Jadi, kueri berikut:
index . term_query ( %i[ title description ] , "hello" )Setara dengan:
index . term_query ( :title , "hello" ) | index . term_query ( :description , "hello" ) Semua pertanyaan mendukung parameter boost yang memungkinkan untuk menabrak posisi dokumen dalam pencarian:
about_cowboys = index . term_query ( :description , "cowboy" , boost : 2.0 )
about_samurai = index . term_query ( :description , "samurai" ) # sorry, Musashi...
index . search ( about_cowboys | about_samurai )smart_query Pencarian smart_query akan mengekstraksi istilah dari string kueri Anda menggunakan tokenizer bidang masing -masing dan mencari indeks untuk dokumen yang berisi istilah tersebut melalui term_query . Jika parameter fuzzy_distance ditentukan, itu akan menggunakan fuzzy_term_query . Juga, ini memungkinkan istilah terakhir belum selesai dengan menggunakan prefix_query .
Jadi, kueri berikut:
index . smart_query ( %i[ en_text ru_text ] , "dollars рубли eur" , fuzzy_distance : 1 )Setara dengan:
t1_en = index . fuzzy_term_query ( :en_text , "dollar" )
t2_en = index . fuzzy_term_query ( :en_text , "рубли" )
t3_en = index . fuzzy_term_query ( :en_text , "eur" )
t3_prefix_en = index . prefix_query ( :en_text , "eur" )
t1_ru = index . fuzzy_term_query ( :ru_text , "dollars" )
t2_ru = index . fuzzy_term_query ( :ru_text , "рубл" )
t3_ru = index . fuzzy_term_query ( :ru_text , "eur" )
t3_prefix_ru = index . prefix_query ( :ru_text , "eur" )
( t1_en & t2_en & ( t3_en | t3_prefix_en ) ) | ( t1_ru & t2_ru & ( t3_ru | t3_prefix_ru ) ) Perhatikan bagaimana kata "dolar" dan "рбли" berasal dari berbeda tergantung pada bidang yang kita cari. Ini dengan asumsi kami memiliki bidang en_text dan ru_text dalam skema kami yang masing -masing menggunakan tokenizer Stemmer Bahasa Inggris dan Rusia.
regex_query regex_query menerima pola regex, tetapi harus menjadi Rust Regex, bukan Ruby Regexp . Jadi, alih -alih index.regex_query(:description, /hel[lp]/) Anda perlu menggunakan index.regex_query(:description, "hel[lp]") . Sebagai catatan, regex_query cukup cepat karena menggunakan peti FST secara internal.
Jadi, kami telah menyebutkan tokenizer lebih dari satu kali. Apa mereka?
Tokenizer adalah apa yang digunakan Tantivy untuk memotong teks Anda ke istilah untuk membangun indeks terbalik. Kemudian Anda dapat mencari indeks dengan istilah -istilah ini. Ini adalah konsep penting untuk dipahami sehingga Anda tidak bingung ketika index.term_query(:description, "Hello") tidak mengembalikan apa pun karena Hello bukan istilah, tapi hello adalah. Anda harus mengekstrak istilah dari kueri sebelum mencari indeks. Saat ini, hanya smart_query yang melakukan itu untuk Anda. Juga, satu -satunya tipe bidang yang tokenized adalah text , jadi untuk bidang string Anda harus menggunakan kecocokan yang tepat (yaitu index.term_query(:title, "Hello") ).
Secara default tokenizer simple digunakan, tetapi Anda dapat menentukan tokenizer yang diinginkan secara global melalui opsi indeks atau secara lokal melalui opsi spesifik lapangan:
en_stemmer = Tantiny :: Tokenizer . new ( :stemmer )
ru_stemmer = Tantiny :: Tokenizer . new ( :stemmer , language : :ru )
Tantiny :: Index . new "/tmp/index" , tokenizer : en_stemmer do
text :description_en
text :description_ru , tokenizer : ru_stemmer
endTokenizer sederhana memotong teks pada tanda baca dan ruang putih, menghilangkan token panjang, dan lebih rendah teks.
tokenizer = Tantiny :: Tokenizer . new ( :simple )
tokenizer . terms ( "Hello World!" ) # ["hello", "world"]Tokenizer Stemmer persis seperti tokenizer sederhana, tetapi dengan stemming tambahan sesuai dengan bahasa yang ditentukan (default ke bahasa Inggris).
tokenizer = Tantiny :: Tokenizer . new ( :stemmer , language : :ru )
tokenizer . terms ( "Привет миру сему!" ) # ["привет", "мир", "сем"]Lihatlah sumber untuk melihat bahasa apa yang didukung.
Ngram Tokenizer memotong teks Anda ke Ngram dengan ukuran tertentu.
tokenizer = Tantiny :: Tokenizer . new ( :ngram , min : 5 , max : 10 , prefix_only : true )
tokenizer . terms ( "Morrowind" ) # ["Morro", "Morrow", "Morrowi", "Morrowin", "Morrowind"] Anda mungkin telah memperhatikan bahwa metode search hanya mengembalikan ID dokumen. Ini dengan desain. Dokumen itu sendiri tidak disimpan dalam indeks. Tantiny adalah perpustakaan minimalis, jadi ia mencoba untuk menjaga hal -hal sederhana. Jika Anda perlu mengambil dokumen lengkap, gunakan toko nilai kunci seperti Redis bersama.
Setelah memeriksa repo, jalankan bin/setup untuk menginstal dependensi. Kemudian, jalankan rake build untuk membangun ekstensi asli, dan kemudian rake spec untuk menjalankan tes. Anda juga dapat menjalankan bin/console untuk prompt interaktif yang akan memungkinkan Anda untuk bereksperimen.
Kami menggunakan komitmen konvensional untuk secara otomatis menghasilkan changelog, menabrak versi semantik, dan untuk menerbitkan dan merilis permata. Yang perlu Anda lakukan adalah tetap berpegang pada konvensi dan CI akan mengurus segala hal lain untuk Anda.
Laporan bug dan permintaan tarik dipersilakan di GitHub di https://github.com/baygeldin/tantiny.
Permata tersedia sebagai open source di bawah ketentuan lisensi MIT.