Mari kita bahas FlexSearch v0.8 mendatang di sini: #415
Mulai Dasar • Referensi API • Indeks Dokumen • Menggunakan Pekerja • Changelog
Anda dapat membantu saya dengan memberikan sumbangan pribadi untuk menjaga proyek ini tetap berjalan dan juga memberikan semua kontribusi untuk menyelesaikan kebutuhan Anda.
Operasi Antitesis LLC
Dalam hal kecepatan pencarian mentah, FlexSearch mengungguli setiap perpustakaan pencarian di luar sana dan juga menyediakan kemampuan pencarian yang fleksibel seperti pencarian multi-bidang, transformasi fonetik, atau pencocokan parsial.
Tergantung pada opsi yang digunakan, ini juga menyediakan indeks yang paling hemat memori. FlexSearch memperkenalkan algoritme penilaian baru yang disebut "indeks kontekstual" berdasarkan arsitektur kamus leksikal yang telah diberi skor sebelumnya yang benar-benar melakukan kueri hingga 1.000.000 kali lebih cepat dibandingkan perpustakaan lain. FlexSearch juga memberi Anda model pemrosesan asinkron non-pemblokiran serta pekerja web untuk melakukan pembaruan atau kueri apa pun pada indeks secara paralel melalui thread seimbang khusus.
Platform yang Didukung:
Perbandingan Perpustakaan "Perjalanan Gulliver":
Plugin (proyek eksternal):
Membangun | Mengajukan | CDN |
flexsearch.bundle.js | Unduh | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.bundle.js |
flexsearch.light.js | Unduh | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.light.js |
flexsearch.kompak.js | Unduh | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.compact.js |
flexsearch.es5.js * | Unduh | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.es5.js |
Modul ES6 | Unduh | Folder /dist/module/ dari repositori Github ini |
* Bundel "flexsearch.es5.js" mencakup polyfill untuk Dukungan EcmaScript 5.
npm install flexsearch
Paket Node.js mencakup semua fitur dari
flexsearch.bundle.js
.
Fitur | flexsearch.bundle.js | flexsearch.kompak.js | flexsearch.light.js |
Preset | ✓ | ✓ | - |
Pencarian Asinkron | ✓ | ✓ | - |
Pekerja (Web + Node.js) | ✓ | - | - |
Indeks Kontekstual | ✓ | ✓ | ✓ |
Dokumen Indeks (Pencarian Lapangan) | ✓ | ✓ | - |
Penyimpanan Dokumen | ✓ | ✓ | - |
Pencocokan Sebagian | ✓ | ✓ | ✓ |
Penilaian Relevansi | ✓ | ✓ | ✓ |
Cache Seimbang Otomatis berdasarkan Popularitas | ✓ | - | - |
Tag | ✓ | - | - |
Saran | ✓ | ✓ | - |
Pencocokan Fonetik | ✓ | ✓ | - |
Rangkaian Karakter/Bahasa yang Dapat Disesuaikan (Matcher, Encoder, Tokenizer, Stemmer, Filter, Split, RTL) | ✓ | ✓ | ✓ |
Indeks Ekspor / Impor | ✓ | - | - |
Ukuran File (gzip) | 6,8 kb | 5,3 kb | 2,9 kb |
Jalankan Perbandingan: Tolok Ukur Kinerja "Gulliver's Travels"
Operasi per detik, lebih tinggi lebih baik, kecuali tes "Memori" yang lebih rendah lebih baik.
Pangkat | Perpustakaan | Ingatan | Kueri (Istilah Tunggal) | Kueri (Multi Istilah) | Kueri (Panjang) | Kueri (Penipuan) | Kueri (Tidak Ditemukan) |
1 | Pencarian Fleksibel | 17 | 7084129 | 1586856 | 511585 | 2017142 | 3202006 |
2 | JSii | 27 | 6564 | 158149 | 61290 | 95098 | 534109 |
3 | Menyeberang | 424 | 20471 | 78780 | 16693 | 225824 | 213754 |
4 | Pencarian JS | 193 | 8221 | 64034 | 10377 | 95830 | 167605 |
5 | Elasticlunr.js | 646 | 5412 | 7573 | 2865 | 23786 | 13982 |
6 | Pencarian Massal | 1021 | 3069 | 3141 | 3333 | 3265 | 21825569 |
7 | Pencarian Mini | 24348 | 4406 | 10945 | 72 | 39989 | 17624 |
8 | bm25 | 15719 | 1429 | 789 | 366 | 884 | 1823 |
9 | Lunr.js | 2219 | 255 | 271 | 272 | 266 | 267 |
10 | Pencarian Fuzzy | 157373 | 53 | 38 | 15 | 32 | 43 |
11 | Sekering | 7641904 | 6 | 2 | 1 | 2 | 3 |
Ada 3 jenis indeks:
Index
adalah indeks kinerja tinggi datar yang menyimpan pasangan id-konten.Worker
/ WorkerIndex
juga merupakan indeks datar yang menyimpan pasangan id-konten tetapi berjalan di latar belakang sebagai thread pekerja khusus.Document
adalah indeks multi-bidang yang dapat menyimpan dokumen JSON yang kompleks (bisa juga ada indeks pekerja).Sebagian besar dari Anda mungkin hanya memerlukan salah satunya sesuai dengan skenario Anda.
< script src =" node_modules/flexsearch/dist/flexsearch.bundle.min.js " > </ script >
< script >
// FlexSearch is available on window.FlexSearch
// Access FlexSearch static methods via bundled export (static class methods of FlexSearch)
const index = FlexSearch . Index ( options ) ;
const document = FlexSearch . Document ( options ) ;
const worker = FlexSearch . Worker ( options ) ;
</ script >
< script type =" module " >
// FlexSearch is NOT available on window.FlexSearch
// Access FlexSearch static methods by importing them explicitly
import Index from "./node_modules/flexsearch/dist/module/index" ;
import Document from "./node_modules/flexsearch/dist/module/document" ;
import Worker from "./node_modules/flexsearch/dist/module/worker" ;
const index = new Index ( options ) ;
const document = new Document ( options ) ;
const worker = new Worker ( options ) ;
</ script >
< script type =" module " >
// FlexSearch is NOT available on window.FlexSearch
// Access FlexSearch static methods via bundled export (static class methods of FlexSearch)
import FlexSearch from "./node_modules/flexsearch/dist/flexsearch.bundle.module.min.js" ;
const index = FlexSearch . Index ( options ) ;
const document = FlexSearch . Document ( options ) ;
const worker = FlexSearch . Worker ( options ) ;
</ script >
Atau melalui CDN:
< script src =" https://cdn.jsdelivr.net/gh/nextapps-de/[email protected]/dist/flexsearch.bundle.min.js " > </ script >
AMD/JS Umum:
var FlexSearch = require ( "./node_modules/flexsearch/dist/flexsearch.bundle.min.js" ) ;
npm install flexsearch
Dalam kode Anda sertakan sebagai berikut:
const { Index , Document , Worker } = require ( "flexsearch" ) ;
const index = new Index ( options ) ;
const document = new Document ( options ) ;
const worker = new Worker ( options ) ;
Atau:
const FlexSearch = require ( "flexsearch" ) ;
const index = new FlexSearch . Index ( options ) ;
const document = new FlexSearch . Document ( options ) ;
const worker = new FlexSearch . Worker ( options ) ;
index . add ( id , text ) ;
index . search ( text ) ;
index . search ( text , limit ) ;
index . search ( text , options ) ;
index . search ( text , limit , options ) ;
index . search ( options ) ;
document . add ( doc ) ;
document . add ( id , doc ) ;
document . search ( text ) ;
document . search ( text , limit ) ;
document . search ( text , options ) ;
document . search ( text , limit , options ) ;
document . search ( options ) ;
worker . add ( id , text ) ;
worker . search ( text ) ;
worker . search ( text , limit ) ;
worker . search ( text , options ) ;
worker . search ( text , limit , options ) ;
worker . search ( text , limit , options , callback ) ;
worker . search ( options ) ;
worker
mewarisi dari tipe Index
dan tidak mewarisi dari tipe Document
. Oleh karena itu, WorkerIndex pada dasarnya berfungsi seperti Indeks FlexSearch standar. Dukungan Pekerja dalam dokumen harus diaktifkan hanya dengan meneruskan opsi yang sesuai selama pembuatan { worker: true }
.
Setiap metode yang dipanggil pada indeks
Worker
diperlakukan sebagai asinkron. Anda akan mendapatkan kembaliPromise
atau Anda dapat memberikan fungsi panggilan balik sebagai parameter terakhir sebagai alternatif.
Metode global:
Metode indeks:
Metode Indeks Pekerja:
Metode dokumen:
* Untuk masing-masing metode tersebut terdapat padanan asinkron:
Versi Asinkron:
Metode async akan mengembalikan Promise
, alternatifnya Anda dapat meneruskan fungsi panggilan balik sebagai parameter terakhir.
Metode export
dan import
selalu async serta setiap metode yang Anda panggil pada Indeks berbasis Pekerja.
FlexSearch sangat dapat disesuaikan. Memanfaatkan opsi yang tepat benar-benar dapat meningkatkan hasil Anda serta penghematan memori dan waktu kueri.
Pilihan | Nilai-nilai | Keterangan | Bawaan |
telah ditentukan sebelumnya | "ingatan" "pertunjukan" "cocok" "skor" "bawaan" | Profil konfigurasi sebagai pintasan atau sebagai dasar untuk pengaturan khusus Anda. | "bawaan" |
tokenisasi | "ketat" "maju" "balik" "penuh" | Mode pengindeksan (tokenizer). Pilih salah satu fungsi bawaan atau teruskan fungsi tokenizer khusus. | "ketat" |
cache | Boolean Nomor | Mengaktifkan/Menonaktifkan dan/atau mengatur kapasitas entri cache. Ketika melewati nomor sebagai batas cache secara otomatis menyeimbangkan entri yang disimpan terkait dengan popularitasnya . Catatan: Saat hanya menggunakan "true", cache tidak memiliki batasan dan pertumbuhan tidak terbatas. | PALSU |
resolusi | Nomor | Mengatur resolusi penilaian (default: 9). | 9 |
konteks | Boolean Opsi Konteks | Aktifkan/Nonaktifkan pengindeksan kontekstual. Saat meneruskan "true" sebagai nilai, ia akan mengambil nilai default untuk konteksnya. | PALSU |
mengoptimalkan | Boolean | Jika diaktifkan, ini menggunakan aliran tumpukan yang dioptimalkan memori untuk indeks. | BENAR |
mendorong | fungsi(arr, str, int) => mengambang | Fungsi peningkatan khusus yang digunakan saat mengindeks konten ke indeks. Fungsi tersebut memiliki tanda tangan ini: Function(words[], term, index) => Float . Ini memiliki 3 parameter di mana Anda mendapatkan array dari semua kata, istilah saat ini dan indeks saat ini di mana istilah tersebut ditempatkan dalam array kata. Anda dapat menerapkan penghitungan Anda sendiri, misalnya kemunculan suatu istilah dan mengembalikan faktor ini (<1 berarti relevansi diturunkan, >1 berarti relevansi meningkat).Catatan: fitur ini saat ini dibatasi dengan menggunakan tokenizer "ketat" saja. | batal |
Opsi dan Pengkodean Khusus Bahasa: | |||
rangkaian karakter | Muatan Charset Tali (kunci) | Berikan payload rangkaian karakter khusus atau teruskan salah satu kunci rangkaian karakter bawaan. | "Latin" |
bahasa | Muatan Bahasa Tali (kunci) | Berikan muatan bahasa khusus atau tanda singkatan bahasa (ISO-3166) dari bahasa bawaan. | batal |
menyandi | PALSU "bawaan" "sederhana" "keseimbangan" "canggih" "tambahan" fungsi(str) => [kata-kata] | Jenis pengkodean. Pilih salah satu fungsi pengkodean bawaan atau berikan fungsi pengkodean khusus. | "bawaan" |
batang | PALSU Rangkaian Fungsi | PALSU | |
menyaring | PALSU Rangkaian Fungsi | PALSU | |
pencocokan | PALSU Rangkaian Fungsi | PALSU | |
Opsi Tambahan untuk Indeks Dokumen: | |||
pekerja | Boolean | Aktifkan/Nonaktifkan dan atur jumlah thread pekerja yang berjalan. | PALSU |
dokumen | Deskriptor Dokumen | Termasuk definisi untuk indeks dan penyimpanan dokumen. |
Pilihan | Nilai-nilai | Keterangan | Bawaan |
resolusi | Nomor | Menetapkan resolusi penilaian untuk konteks (default: 1). | 1 |
kedalaman | PALSU Nomor | Aktifkan/Nonaktifkan pengindeksan kontekstual dan juga tetapkan jarak relevansi kontekstual. Kedalaman adalah jumlah maksimum kata/tanda suatu istilah yang dianggap relevan. | 1 |
dua arah | Boolean | Menetapkan hasil pencarian dua arah. Jika diaktifkan dan teks sumber berisi "topi merah", maka akan ditemukan kueri "topi merah" dan "topi merah". | BENAR |
Pilihan | Nilai-nilai | Keterangan | Bawaan |
pengenal | Rangkaian | "pengenal"" | |
menandai | PALSU Rangkaian | "menandai" | |
indeks | Rangkaian Larik<String> Array<Objek> | ||
toko | Boolean Rangkaian Larik<String> | PALSU |
Pilihan | Nilai-nilai | Keterangan | Bawaan |
membelah | PALSU RegExp Rangkaian | Aturan untuk memisahkan kata saat menggunakan tokenizer non-kustom (bawaan misalnya "teruskan"). Gunakan string/char atau gunakan ekspresi reguler (default: /W+/ ). | /[W_]+/ |
rtl | Boolean | Mengaktifkan pengkodean Kanan-Ke-Kiri. | PALSU |
menyandi | fungsi(str) => [kata-kata] | Fungsi pengkodean khusus. | /lang/latin/default.js |
Pilihan | Nilai-nilai | Keterangan |
batang | PALSU Rangkaian Fungsi | Menonaktifkan atau meneruskan tanda singkatan bahasa (ISO-3166) atau objek khusus. |
menyaring | PALSU Rangkaian Fungsi | Menonaktifkan atau meneruskan tanda singkatan bahasa (ISO-3166) atau larik khusus. |
pencocokan | PALSU Rangkaian Fungsi | Nonaktifkan atau teruskan tanda singkatan bahasa (ISO-3166) atau larik khusus. |
Pilihan | Nilai-nilai | Keterangan | Bawaan |
membatasi | nomor | Menetapkan batas hasil. | 100 |
mengimbangi | nomor | Terapkan offset (lewati item). | 0 |
menyarankan | Boolean | Mengaktifkan saran dalam hasil. | PALSU |
Pilihan | Nilai-nilai | Keterangan | Bawaan |
indeks | Rangkaian Larik<String> Array<Objek> | Menetapkan bidang dokumen yang harus dicari. Jika tidak ada bidang yang disetel, semua bidang akan dicari. Opsi khusus per bidang juga didukung. | |
menandai | Rangkaian Larik<String> | Menetapkan bidang dokumen yang harus dicari. Jika tidak ada bidang yang disetel, semua bidang akan dicari. Opsi khusus per bidang juga didukung. | PALSU |
memperkaya | Boolean | Perkaya ID dari hasil dengan dokumen terkait. | PALSU |
bodoh | "Dan" "atau" | Menetapkan operator logis yang digunakan saat mencari melalui beberapa bidang atau tag. | "atau" |
Tokenizer memengaruhi memori yang diperlukan juga sebagai waktu kueri dan fleksibilitas pencocokan parsial. Cobalah untuk memilih tokenizer paling atas yang sesuai dengan kebutuhan Anda:
Pilihan | Keterangan | Contoh | Faktor Memori (n = panjang kata) |
"ketat" | indeks seluruh kata | foobar | * 1 |
"maju" | secara bertahap mengindeks kata-kata ke arah depan | fo obarfoob ar | * N |
"balik" | mengindeks kata secara bertahap di kedua arah | foob ar untuk obar | * 2n - 1 |
"penuh" | indeks setiap kemungkinan kombinasi | untuk oba rf oob ar | *n* (n - 1) |
Pengkodean juga memengaruhi memori yang diperlukan seperti waktu kueri dan kecocokan fonetik. Cobalah untuk memilih encoder paling atas yang sesuai dengan kebutuhan Anda, atau berikan encoder khusus:
Pilihan | Keterangan | Positif Palsu | Kompresi |
PALSU | Matikan pengkodean | TIDAK | 0% |
"bawaan" | Pengkodean tidak peka huruf besar-kecil | TIDAK | 0% |
"sederhana" | Pengkodean tidak peka huruf besar-kecil Normalisasi rangkaian karakter | TIDAK | ~ 3% |
"keseimbangan" | Pengkodean tidak peka huruf besar-kecil Normalisasi rangkaian karakter Transformasi literal | TIDAK | ~ 30% |
"canggih" | Pengkodean tidak peka huruf besar-kecil Normalisasi rangkaian karakter Transformasi literal Normalisasi fonetik | TIDAK | ~ 40% |
"tambahan" | Pengkodean tidak peka huruf besar-kecil Normalisasi rangkaian karakter Transformasi literal Normalisasi fonetik Transformasi Soundex | Ya | ~ 65% |
fungsi() | Berikan pengkodean khusus melalui function(string):[words] |
var index = new Index ( ) ;
Buat indeks baru dan pilih salah satu preset:
var index = new Index ( "performance" ) ;
Buat indeks baru dengan opsi khusus:
var index = new Index ( {
charset : "latin:extra" ,
tokenize : "reverse" ,
resolution : 9
} ) ;
Buat indeks baru dan perluas preset dengan opsi khusus:
var index = new FlexSearch ( {
preset : "memory" ,
tokenize : "forward" ,
resolution : 5
} ) ;
Lihat semua opsi khusus yang tersedia.
Setiap konten yang harus ditambahkan ke indeks memerlukan ID. Jika konten Anda tidak memiliki ID, maka Anda perlu membuatnya dengan meneruskan indeks atau hitungan atau sesuatu yang lain sebagai ID (nilai dari tipe number
sangat disarankan). ID tersebut adalah referensi unik ke konten tertentu. Ini penting ketika Anda memperbarui atau menambahkan konten melalui ID yang ada. Jika referensi tidak menjadi masalah, Anda cukup menggunakan sesuatu yang sederhana seperti count++
.
Indeks. tambahkan(id, string)
index . add ( 0 , "John Doe" ) ;
Indeks. pencarian(string | pilihan, <batas>, <pilihan>)
index . search ( "John" ) ;
Batasi hasilnya:
index . search ( "John" , 10 ) ;
Anda dapat memeriksa apakah suatu ID sudah diindeks dengan:
if ( index . contain ( 1 ) ) {
console . log ( "ID is already in index" ) ;
}
Anda dapat memanggil setiap metode dalam versi async-nya, misalnya index.addAsync
atau index.searchAsync
.
Anda dapat menetapkan callback ke setiap fungsi async:
index . addAsync ( id , content , function ( ) {
console . log ( "Task Done" ) ;
} ) ;
index . searchAsync ( query , function ( result ) {
console . log ( "Results: " , result ) ;
} ) ;
Atau jangan meneruskan fungsi panggilan balik dan mendapatkan kembali Promise
sebagai gantinya:
index . addAsync ( id , content ) . then ( function ( ) {
console . log ( "Task Done" ) ;
} ) ;
index . searchAsync ( query ) . then ( function ( result ) {
console . log ( "Results: " , result ) ;
} ) ;
Atau gunakan async
dan await
:
async function add ( ) {
await index . addAsync ( id , content ) ;
console . log ( "Task Done" ) ;
}
async function search ( ) {
const results = await index . searchAsync ( query ) ;
console . log ( "Results: " , result ) ;
}
Anda dapat menambahkan konten ke indeks yang ada seperti:
index . append ( id , content ) ;
Ini tidak akan menimpa konten lama yang diindeks seperti yang akan dilakukan saat melakukan index.update(id, content)
. Ingatlah bahwa index.add(id, content)
juga akan melakukan "pembaruan" ketika id sudah diindeks.
Konten yang ditambahkan akan memiliki konteksnya sendiri dan juga resolution
penuhnya sendiri. Oleh karena itu, relevansinya tidak ditumpuk tetapi mendapat konteksnya sendiri.
Mari kita ambil contoh ini:
index . add ( 0 , "some index" ) ;
index . append ( 0 , "some appended content" ) ;
index . add ( 1 , "some text" ) ;
index . append ( 1 , "index appended content" ) ;
Saat Anda menanyakan index.search("index")
maka Anda akan mendapatkan indeks id 1 sebagai entri pertama dalam hasil, karena konteksnya dimulai dari nol untuk data yang ditambahkan (tidak ditumpuk ke konteks lama) dan di sini "indeks " adalah istilah pertama.
Jika Anda tidak menginginkan perilaku ini, cukup gunakan index.add(id, content)
standar dan berikan konten lengkap.
Indeks. perbarui(id, string)
index . update ( 0 , "Max Miller" ) ;
Indeks. hapus(id)
index . remove ( 0 ) ;
Tokenizer membagi kata/istilah menjadi komponen atau sebagian.
Tentukan tokenizer khusus pribadi selama pembuatan/inisialisasi:
var index = new FlexSearch ( {
tokenize : function ( str ) {
return str . split ( / s-/ / g ) ;
}
} ) ;
Fungsi tokenizer mendapatkan string sebagai parameter dan harus mengembalikan array string yang mewakili kata atau istilah. Dalam beberapa bahasa, setiap karakter adalah sebuah istilah dan juga tidak dipisahkan melalui spasi.
Stemmer: beberapa mutasi linguistik dari kata yang sama (misalnya “run” dan “running”)
Filter: daftar hitam kata-kata yang akan disaring dari pengindeksan sama sekali (misalnya "dan", "ke" atau "menjadi")
Tetapkan stemmer atau filter khusus pribadi selama pembuatan/inisialisasi:
var index = new FlexSearch ( {
stemmer : {
// object {key: replacement}
"ational" : "ate" ,
"tional" : "tion" ,
"enci" : "ence" ,
"ing" : ""
} ,
filter : [
// array blacklist
"in" ,
"into" ,
"is" ,
"isn't" ,
"it" ,
"it's"
]
} ) ;
Menggunakan filter khusus, misalnya:
var index = new FlexSearch ( {
filter : function ( value ) {
// just add values with length > 1 to the index
return value . length > 1 ;
}
} ) ;
Atau tetapkan stemmer/filter secara global ke suatu bahasa:
Stemmer diteruskan sebagai objek (pasangan nilai kunci), filter sebagai array.
FlexSearch . registerLanguage ( "us" , {
stemmer : { /* ... */ } ,
filter : [ /* ... */ ]
} ) ;
Atau gunakan stemmer atau filter yang telah ditentukan sebelumnya untuk bahasa pilihan Anda:
< html >
< head >
< script src =" js/flexsearch.bundle.js " > </ script >
< script src =" js/lang/en.min.js " > </ script >
< script src =" js/lang/de.min.js " > </ script >
</ head >
...
Sekarang Anda dapat menetapkan stemmer bawaan selama pembuatan/inisialisasi:
var index_en = new FlexSearch . Index ( {
language : "en"
} ) ;
var index_de = new FlexSearch . Index ( {
language : "de"
} ) ;
Di Node.js semua file paket bahasa bawaan tersedia:
const { Index } = require ( "flexsearch" ) ;
var index_en = new Index ( {
language : "en"
} ) ;
Setel tokenizer setidaknya ke "mundur" atau "penuh" saat menggunakan RTL.
Cukup setel bidang "rtl" ke true dan gunakan tokenizer yang kompatibel:
var index = new Index ( {
encode : str => str . toLowerCase ( ) . split ( / [^a-z]+ / ) ,
tokenize : "reverse" ,
rtl : true
} ) ;
Tetapkan tokenizer khusus yang sesuai dengan kebutuhan Anda, misalnya:
var index = FlexSearch . create ( {
encode : str => str . replace ( / [x00-x7F] / g , "" ) . split ( "" )
} ) ;
Anda juga dapat meneruskan fungsi encoder khusus untuk menerapkan beberapa transformasi linguistik.
index . add ( 0 , "一个单词" ) ;
var results = index . search ( "单词" ) ;
Dengan asumsi dokumen kita memiliki struktur data seperti ini:
{
"id" : 0 ,
"content" : " some text "
}
Sintaks lama FlexSearch v0.6.3 ( tidak didukung lagi! ):
const index = new Document ( {
doc : {
id : "id" ,
field : [ "content" ]
}
} ) ;
Deskriptor dokumen sedikit berubah, tidak ada lagi cabang
field
, melainkan hanya menerapkan satu tingkat lebih tinggi, sehinggakey
menjadi anggota utama opsi.
Untuk sintaks baru, bidang "doc" diubah namanya menjadi document
dan bidang "field" diubah namanya menjadi index
:
const index = new Document ( {
document : {
id : "id" ,
index : [ "content" ]
}
} ) ;
index . add ( {
id : 0 ,
content : "some text"
} ) ;
Bidang id
menjelaskan lokasi ID atau kunci unik di dalam dokumen Anda. Kunci default mendapatkan nilai id
secara default ketika tidak diteruskan, sehingga Anda dapat mempersingkat contoh dari atas menjadi:
const index = new Document ( {
document : {
index : [ "content" ]
}
} ) ;
index
anggota memiliki daftar bidang yang ingin Anda indeks dari dokumen Anda. Saat hanya memilih satu bidang, maka Anda dapat meneruskan sebuah string. Ketika juga menggunakan id
kunci default maka ini disingkat menjadi:
const index = new Document ( { document : "content" } ) ;
index . add ( { id : 0 , content : "some text" } ) ;
Dengan asumsi Anda memiliki beberapa bidang, Anda dapat menambahkan beberapa bidang ke indeks:
var docs = [ {
id : 0 ,
title : "Title A" ,
content : "Body A"
} , {
id : 1 ,
title : "Title B" ,
content : "Body B"
} ] ;
const index = new Document ( {
id : "id" ,
index : [ "title" , "content" ]
} ) ;
Anda dapat memberikan opsi khusus untuk setiap bidang:
const index = new Document ( {
id : "id" ,
index : [ {
field : "title" ,
tokenize : "forward" ,
optimize : true ,
resolution : 9
} , {
field : "content" ,
tokenize : "strict" ,
optimize : true ,
resolution : 5 ,
minlength : 3 ,
context : {
depth : 1 ,
resolution : 3
}
} ]
} ) ;
Opsi bidang diwarisi ketika opsi global juga diteruskan, misalnya:
const index = new Document ( {
tokenize : "strict" ,
optimize : true ,
resolution : 9 ,
document : {
id : "id" ,
index : [ {
field : "title" ,
tokenize : "forward"
} , {
field : "content" ,
minlength : 3 ,
context : {
depth : 1 ,
resolution : 3
}
} ]
}
} ) ;
Catatan: Opsi konteks dari bidang "konten" juga diwarisi oleh opsi bidang terkait, sedangkan opsi bidang ini diwarisi oleh opsi global.
Asumsikan susunan dokumen terlihat lebih kompleks (memiliki cabang bersarang, dll.), misalnya:
{
"record" : {
"id" : 0 ,
"title" : " some title " ,
"content" : {
"header" : " some text " ,
"footer" : " some text "
}
}
}
Kemudian gunakan notasi yang dipisahkan titik dua root:child:child
untuk mendefinisikan hierarki dalam deskriptor dokumen:
const index = new Document ( {
document : {
id : "record:id" ,
index : [
"record:title" ,
"record:content:header" ,
"record:content:footer"
]
}
} ) ;
Cukup tambahkan bidang yang ingin Anda tanyakan. Jangan menambahkan bidang ke indeks, Anda hanya perlu hasilnya (tetapi tidak melakukan kueri terhadap). Untuk tujuan ini Anda dapat menyimpan dokumen secara independen dari indeksnya (baca di bawah).
Saat Anda ingin melakukan kueri melalui suatu bidang, Anda harus memasukkan kunci persis dari bidang yang telah Anda tetapkan di doc
sebagai nama bidang (dengan sintaksis titik dua):
index . search ( query , {
index : [
"record:title" ,
"record:content:header" ,
"record:content:footer"
]
} ) ;
Sama seperti:
index . search ( query , [
"record:title" ,
"record:content:header" ,
"record:content:footer"
] ) ;
Menggunakan opsi khusus bidang:
index . search ( [ {
field : "record:title" ,
query : "some query" ,
limit : 100 ,
suggest : true
} , {
field : "record:title" ,
query : "some other query" ,
limit : 100 ,
suggest : true
} ] ) ;
Anda dapat melakukan pencarian melalui bidang yang sama dengan kueri yang berbeda.
Saat meneruskan opsi khusus bidang, Anda perlu menyediakan konfigurasi lengkap untuk setiap bidang. Mereka tidak diwarisi seperti deskriptor dokumen.
Anda harus mengikuti 2 aturan untuk dokumen Anda:
[ // <-- not allowed as document start!
{
"id" : 0 ,
"title" : "title"
}
]
{
"records" : [ // <-- not allowed when ID or tag lives inside!
{
"id" : 0 ,
"title" : "title"
}
]
}
Berikut contoh dokumen kompleks yang didukung:
{
"meta" : {
"tag" : " cat " ,
"id" : 0
},
"contents" : [
{
"body" : {
"title" : " some title " ,
"footer" : " some text "
},
"keywords" : [ " some " , " key " , " words " ]
},
{
"body" : {
"title" : " some title " ,
"footer" : " some text "
},
"keywords" : [ " some " , " key " , " words " ]
}
]
}
Deskriptor dokumen yang sesuai (ketika semua bidang harus diindeks) terlihat seperti:
const index = new Document ( {
document : {
id : "meta:id" ,
tag : "meta:tag" ,
index : [
"contents[]:body:title" ,
"contents[]:body:footer" ,
"contents[]:keywords"
]
}
} ) ;
Sekali lagi, saat mencari, Anda harus menggunakan string yang dipisahkan titik dua yang sama dari definisi bidang Anda.
index . search ( query , {
index : "contents[]:body:title"
} ) ;
Contoh ini melanggar kedua aturan di atas:
[ // <-- not allowed as document start!
{
"tag" : "cat" ,
"records" : [ // <-- not allowed when ID or tag lives inside!
{
"id" : 0 ,
"body" : {
"title" : "some title" ,
"footer" : "some text"
} ,
"keywords" : [ "some" , "key" , "words" ]
} ,
{
"id" : 1 ,
"body" : {
"title" : "some title" ,
"footer" : "some text"
} ,
"keywords" : [ "some" , "key" , "words" ]
}
]
}
]
Anda perlu menerapkan semacam normalisasi struktur.
Solusi untuk struktur data tersebut terlihat seperti ini:
const index = new Document ( {
document : {
id : "record:id" ,
tag : "tag" ,
index : [
"record:body:title" ,
"record:body:footer" ,
"record:body:keywords"
]
}
} ) ;
function add ( sequential_data ) {
for ( let x = 0 , data ; x < sequential_data . length ; x ++ ) {
data = sequential_data [ x ] ;
for ( let y = 0 , record ; y < data . records . length ; y ++ ) {
record = data . records [ y ] ;
index . add ( {
id : record . id ,
tag : data . tag ,
record : record
} ) ;
}
}
}
// now just use add() helper method as usual:
add ( [ {
// sequential structured data
// take the data example above
} ] ) ;
Anda dapat melewati loop pertama ketika data dokumen Anda hanya memiliki satu indeks sebagai array luar.
Tambahkan dokumen ke indeks:
index . add ( {
id : 0 ,
title : "Foo" ,
content : "Bar"
} ) ;
Perbarui indeks dengan satu objek atau serangkaian objek:
index . update ( {
data : {
id : 0 ,
title : "Foo" ,
body : {
content : "Bar"
}
}
} ) ;
Hapus satu objek atau serangkaian objek dari indeks:
index . remove ( docs ) ;
Ketika id diketahui, Anda juga dapat menghapusnya dengan (lebih cepat):
index . remove ( id ) ;
Pada contoh kompleks di atas, bidang keywords
adalah array tetapi di sini markupnya tidak memiliki tanda kurung seperti keywords[]
. Itu juga akan mendeteksi array tetapi alih-alih menambahkan setiap entri ke konteks baru, array akan digabungkan ke dalam string besar dan ditambahkan ke indeks.
Perbedaan dari kedua jenis penambahan isi array ini adalah relevansinya saat mencari. Saat menambahkan setiap item array melalui append()
ke konteksnya sendiri dengan menggunakan sintaks field[]
, maka relevansi entri terakhir bersamaan dengan entri pertama. Jika Anda meninggalkan tanda kurung di notasi, array akan digabungkan menjadi satu string yang dipisahkan spasi. Di sini entri pertama memiliki relevansi tertinggi, sedangkan entri terakhir memiliki relevansi terendah.
Jadi dengan asumsi kata kunci dari contoh di atas telah diurutkan berdasarkan relevansinya dengan popularitasnya, maka Anda ingin mempertahankan urutan ini (informasi relevansi). Untuk tujuan ini jangan menambahkan tanda kurung pada notasi. Jika tidak, entri akan diambil dalam konteks penilaian yang baru (urutan lama akan hilang).
Anda juga dapat meninggalkan notasi braket untuk kinerja yang lebih baik dan jejak memori yang lebih kecil. Gunakan ketika Anda tidak memerlukan rincian relevansi dari entri.
Cari melalui semua bidang:
index . search ( query ) ;
Cari melalui bidang tertentu:
index . search ( query , { index : "title" } ) ;
Telusuri serangkaian bidang tertentu:
index . search ( query , { index : [ "title" , "content" ] } ) ;
Sama seperti:
index . search ( query , [ "title" , "content" ] ) ;
Berikan pengubah dan kueri khusus ke setiap bidang:
index . search ( [ {
field : "content" ,
query : "some query" ,
limit : 100 ,
suggest : true
} , {
field : "content" ,
query : "some other query" ,
limit : 100 ,
suggest : true
} ] ) ;
Anda dapat melakukan pencarian melalui bidang yang sama dengan kueri yang berbeda.
Lihat semua opsi pencarian lapangan yang tersedia.
Skema kumpulan hasil:
fields[] => { field, result[] => { document }}
Indeks pertama adalah array bidang tempat kueri diterapkan. Masing-masing bidang ini memiliki catatan (objek) dengan 2 properti "bidang" dan "hasil". "Hasil" juga berupa array dan menyertakan hasil untuk bidang khusus ini. Hasilnya bisa berupa serangkaian ID atau diperkaya dengan data dokumen yang disimpan.
Kumpulan hasil yang tidak diperkaya sekarang terlihat seperti:
[ {
field : "title" ,
result : [ 0 , 1 , 2 ]
} , {
field : "content" ,
result : [ 3 , 4 , 5 ]
} ]
Kumpulan hasil yang diperkaya sekarang terlihat seperti:
[ {
field : "title" ,
result : [
{ id : 0 , doc : { /* document */ } } ,
{ id : 1 , doc : { /* document */ } } ,
{ id : 2 , doc : { /* document */ } }
]
} , {
field : "content" ,
result : [
{ id : 3 , doc : { /* document */ } } ,
{ id : 4 , doc : { /* document */ } } ,
{ id : 5 , doc : { /* document */ } }
]
} ]
Saat menggunakan pluck
alih-alih "bidang", Anda dapat secara eksplisit memilih hanya satu bidang dan mendapatkan kembali representasi datar:
index . search ( query , { pluck : "title" , enrich : true } ) ;
[
{ id : 0 , doc : { /* document */ } } ,
{ id : 1 , doc : { /* document */ } } ,
{ id : 2 , doc : { /* document */ } }
]
Kumpulan hasil ini merupakan pengganti "pencarian boolean". Daripada menerapkan logika bool ke objek bersarang, Anda dapat menerapkan logika Anda sendiri di atas kumpulan hasil secara dinamis. Ini membuka banyak kemampuan tentang cara Anda memproses hasilnya. Oleh karena itu, hasil-hasil di lapangan tidak lagi dihimpun menjadi satu hasil. Itu menyimpan beberapa informasi penting, seperti nama bidang serta relevansi setiap hasil bidang yang tidak tercampur lagi.
Pencarian bidang akan menerapkan kueri dengan logika boolean "atau" secara default. Setiap bidang memiliki hasil sendiri untuk kueri yang diberikan.
Ada satu situasi di mana properti bool
masih didukung. Saat Anda ingin mengganti logika default "atau" dari bidang pencarian menjadi "dan", misalnya:
index . search ( query , {
index : [ "title" , "content" ] ,
bool : "and"
} ) ;
Anda hanya akan mendapatkan hasil yang berisi kueri di kedua bidang. Itu saja.
Seperti key
untuk ID, cukup tentukan jalur ke tag:
const index = new Document ( {
document : {
id : "id" ,
tag : "tag" ,
index : "content"
}
} ) ;
index . add ( {
id : 0 ,
tag : "cat" ,
content : "Some content ..."
} ) ;
Data Anda juga dapat memiliki beberapa tag sebagai sebuah array:
index . add ( {
id : 1 ,
tag : [ "animal" , "dog" ] ,
content : "Some content ..."
} ) ;
Anda dapat melakukan pencarian khusus tag dengan:
index . search ( query , {
index : "content" ,
tag : "animal"
} ) ;
Ini hanya memberi Anda hasil yang ditandai dengan tag yang diberikan.
Gunakan beberapa tag saat mencari:
index . search ( query , {
index : "content" ,
tag : [ "cat" , "dog" ]
} ) ;
Ini memberi Anda hasil yang ditandai dengan salah satu tag yang diberikan.
Beberapa tag akan diterapkan sebagai boolean "atau" secara default. Itu hanya perlu salah satu tag untuk ada.
Ini adalah situasi lain dimana properti bool
masih didukung. Saat Anda ingin mengganti logika default "atau" dari pencarian tag menjadi "dan", misalnya:
index . search ( query , {
index : "content" ,
tag : [ "dog" , "animal" ] ,
bool : "and"
} ) ;
Anda hanya akan mendapatkan hasil yang berisi kedua tag (dalam contoh ini hanya ada satu catatan yang memiliki tag "anjing" dan "hewan").
Anda juga dapat mengambil hasil dari satu atau beberapa tag ketika tidak ada kueri yang diteruskan:
index . search ( { tag : [ "cat" , "dog" ] } ) ;
Dalam hal ini, kumpulan hasil terlihat seperti:
[ {
tag : "cat" ,
result : [ /* all cats */ ]
} , {
tag : "dog" ,
result : [ /* all dogs */ ]
} ]
Secara default, setiap kueri dibatasi hingga 100 entri. Kueri yang tidak terbatas menyebabkan masalah. Anda perlu menetapkan batas sebagai opsi untuk menyesuaikan ukurannya.
Anda dapat mengatur batas dan offset untuk setiap kueri:
index . search ( query , { limit : 20 , offset : 100 } ) ;
Anda tidak dapat menghitung terlebih dahulu ukuran kumpulan hasil. Itu adalah batasan dari desain FlexSearch. Ketika Anda benar-benar membutuhkan penghitungan semua hasil yang dapat Anda buka halamannya, cukup tetapkan batas yang cukup tinggi dan dapatkan kembali semua hasil dan terapkan offset paging Anda secara manual (ini juga berfungsi di sisi server). FlexSearch cukup cepat sehingga hal ini tidak menjadi masalah.
Hanya indeks dokumen yang dapat memiliki penyimpanan. Anda dapat menggunakan indeks dokumen alih-alih indeks datar untuk mendapatkan fungsi ini juga ketika hanya menyimpan pasangan ID-konten.
Anda dapat menentukan secara mandiri bidang mana yang harus diindeks dan bidang mana yang harus disimpan. Dengan cara ini Anda dapat mengindeks bidang yang tidak boleh disertakan dalam hasil pencarian.
Jangan gunakan toko ketika: 1. array ID karena hasilnya cukup baik, atau 2. Anda sudah memiliki konten/dokumen yang disimpan di tempat lain (di luar indeks).
Ketika atribut
store
disetel, Anda harus menyertakan semua bidang yang harus disimpan secara eksplisit (bertindak seperti daftar putih).
Jika atribut
store
tidak disetel, dokumen asli disimpan sebagai cadangan.
Ini akan menambahkan seluruh konten asli ke toko:
const index = new Document ( {
document : {
index : "content" ,
store : true
}
} ) ;
index . add ( { id : 0 , content : "some text" } ) ;
Anda bisa mendapatkan dokumen yang diindeks dari toko:
var data = index . get ( 1 ) ;
Anda dapat memperbarui/mengubah konten toko secara langsung tanpa mengubah indeks dengan:
index . set ( 1 , data ) ;
Untuk mengupdate store dan juga mengupdate indeks maka gunakan saja index.update
, index.add
atau index.append
.
Saat Anda melakukan kueri, apakah itu indeks dokumen atau indeks datar, maka Anda akan selalu mendapatkan kembali serangkaian ID.
Secara opsional, Anda dapat memperkaya hasil kueri secara otomatis dengan konten yang disimpan dengan:
index . search ( query , { enrich : true } ) ;
Hasil Anda sekarang terlihat seperti:
[ {
id : 0 ,
doc : { /* content from store */ }
} , {
id : 1 ,
doc : { /* content from store */ }
} ]
Ini hanya akan menambahkan bidang tertentu dari dokumen ke penyimpanan (ID tidak perlu disimpan):
const index = new Document ( {
document : {
index : "content" ,
store : [ "author" , "email" ]
}
} ) ;
index . add ( id , content ) ;
Anda dapat mengkonfigurasi secara mandiri apa yang harus diindeks dan apa yang harus disimpan. Sangat disarankan untuk memanfaatkan ini kapan pun Anda bisa.
Berikut contoh berguna dalam mengonfigurasi dokumen dan penyimpanan:
const index = new Document ( {
document : {
index : "content" ,
store : [ "author" , "email" ]
}
} ) ;
index . add ( {
id : 0 ,
author : "Jon Doe" ,
email : "[email protected]" ,
content : "Some content for the index ..."
} ) ;
Anda dapat melakukan kueri melalui konten dan akan mendapatkan kembali nilai yang disimpan:
index . search ( "some content" , { enrich : true } ) ;
Hasil Anda sekarang terlihat seperti:
[ {
field : "content" ,
result : [ {
id : 0 ,
doc : {
author : "Jon Doe" ,
email : "[email protected]" ,
}
} ]
} ]
Bidang "penulis" dan "email" tidak diindeks.
Cukup metode berantai seperti:
var index = FlexSearch . create ( )
. addMatcher ( { 'â' : 'a' } )
. add ( 0 , 'foo' )
. add ( 1 , 'bar' ) ;
index . remove ( 0 ) . update ( 1 , 'foo' ) . add ( 2 , 'foobar' ) ;
Catatan: Fitur ini dinonaktifkan secara default karena penggunaan memorinya yang diperpanjang. Baca di sini untuk mendapatkan informasi lebih lanjut tentang dan cara mengaktifkan.
FlexSearch memperkenalkan mekanisme penilaian baru yang disebut Pencarian Kontekstual yang ditemukan oleh Thomas Wilkerling, penulis perpustakaan ini. Pencarian Kontekstual secara luar biasa meningkatkan kueri ke tingkat yang baru tetapi juga memerlukan beberapa memori tambahan (tergantung pada kedalaman ). Ide dasar dari konsep ini adalah untuk membatasi relevansi berdasarkan konteksnya, bukan menghitung relevansi berdasarkan keseluruhan dokumen yang bersangkutan. Dengan cara ini penelusuran kontekstual juga meningkatkan hasil kueri berbasis relevansi pada sejumlah besar data teks.
Buat indeks dan gunakan konteks default:
var index = new FlexSearch ( {
tokenize : "strict" ,
context : true
} ) ;
Buat indeks dan terapkan opsi khusus untuk konteksnya:
var index = new FlexSearch ( {
tokenize : "strict" ,
context : {
resolution : 5 ,
depth : 3 ,
bidirectional : true
}
} ) ;
Hanya tokenizer "ketat" yang sebenarnya didukung oleh indeks kontekstual.
Indeks kontekstual memerlukan jumlah memori tambahan tergantung pada kedalaman.
Anda perlu menginisialisasi cache dan batasnya selama pembuatan indeks:
const index = new Index ( { cache : 100 } ) ;
const results = index . searchCache ( query ) ;
Skenario umum untuk menggunakan cache adalah pelengkapan otomatis atau pencarian instan saat mengetik.
Saat meneruskan nomor sebagai batas, cache secara otomatis menyeimbangkan entri yang disimpan terkait dengan popularitasnya.
Saat hanya menggunakan "true", cache tidak dibatasi dan bekerja sebenarnya 2-3 kali lebih cepat (karena penyeimbang tidak harus dijalankan).
Model pekerja baru dari v0.7.0 dibagi menjadi "bidang" dari dokumen (1 pekerja = 1 indeks bidang). Dengan cara ini pekerja menjadi mampu menyelesaikan tugas (subtugas) secara tuntas. Kelemahan dari paradigma ini adalah mereka mungkin tidak seimbang sempurna dalam menyimpan konten (bidang mungkin memiliki panjang konten yang berbeda). Di sisi lain, tidak ada indikasi bahwa menyeimbangkan penyimpanan memberikan keuntungan (semuanya memerlukan jumlah total yang sama).
Saat menggunakan indeks dokumen, terapkan saja opsi "pekerja":
const index = new Document ( {
index : [ "tag" , "name" , "title" , "text" ] ,
worker : true
} ) ;
index . add ( {
id : 1 , tag : "cat" , name : "Tom" , title : "some" , text : "some"
} ) . add ( {
id : 2 , tag : "dog" , name : "Ben" , title : "title" , text : "content"
} ) . add ( {
id : 3 , tag : "cat" , name : "Max" , title : "to" , text : "to"
} ) . add ( {
id : 4 , tag : "dog" , name : "Tim" , title : "index" , text : "index"
} ) ;
Worker 1: { 1: "cat", 2: "dog", 3: "cat", 4: "dog" }
Worker 2: { 1: "Tom", 2: "Ben", 3: "Max", 4: "Tim" }
Worker 3: { 1: "some", 2: "title", 3: "to", 4: "index" }
Worker 4: { 1: "some", 2: "content", 3: "to", 4: "index" }
Saat Anda melakukan pencarian lapangan di semua bidang, maka tugas ini diseimbangkan dengan sempurna melalui semua pekerja, yang dapat menyelesaikan subtugasnya secara mandiri.
Di atas kita telah melihat bahwa dokumen akan membuat pekerja secara otomatis untuk setiap bidang. Anda juga dapat membuat WorkerIndex secara langsung (sama seperti menggunakan Index
, bukan Document
).
Gunakan sebagai modul ES6:
import WorkerIndex from "./worker/index.js" ;
const index = new WorkerIndex ( options ) ;
index . add ( 1 , "some" )
. add ( 2 , "content" )
. add ( 3 , "to" )
. add ( 4 , "index" ) ;
Atau ketika versi paket digunakan sebagai gantinya:
var index = new FlexSearch . Worker ( options ) ;
index . add ( 1 , "some" )
. add ( 2 , "content" )
. add ( 3 , "to" )
. add ( 4 , "index" ) ;
WorkerIndex seperti itu berfungsi hampir sama dengan instance Index
yang dibuat.
WorkerIndex hanya mendukung varian
async
dari semua metode. Itu berarti ketika Anda memanggilindex.search()
pada WorkerIndex, ini juga akan bekerja secara asinkron dengan cara yang sama seperti yang dilakukanindex.searchAsync()
.
Model pekerja untuk Node.js didasarkan pada "utas pekerja" dan bekerja dengan cara yang persis sama:
const { Document } = require ( "flexsearch" ) ;
const index = new Document ( {
index : [ "tag" , "name" , "title" , "text" ] ,
worker : true
} ) ;
Atau buat satu instance pekerja untuk indeks non-dokumen:
const { Worker } = require ( "flexsearch" ) ;
const index = new Worker ( { options } ) ;
Seorang pekerja akan selalu tampil sebagai async. Pada panggilan metode kueri, Anda harus selalu menangani janji yang dikembalikan (misalnya menggunakan await
) atau meneruskan fungsi panggilan balik sebagai parameter terakhir.
const index = new Document ( {
index : [ "tag" , "name" , "title" , "text" ] ,
worker : true
} ) ;
Semua permintaan dan subtugas akan berjalan secara paralel (prioritaskan "semua tugas selesai"):
index . searchAsync ( query , callback ) ;
index . searchAsync ( query , callback ) ;
index . searchAsync ( query , callback ) ;
Juga (prioritaskan "semua tugas selesai"):
index . searchAsync ( query ) . then ( callback ) ;
index . searchAsync ( query ) . then ( callback ) ;
index . searchAsync ( query ) . then ( callback ) ;
Atau ketika Anda hanya memiliki satu panggilan balik ketika semua permintaan selesai, cukup gunakan Promise.all()
yang juga memprioritaskan "semua tugas selesai":
Promise . all ( [
index . searchAsync ( query ) ,
index . searchAsync ( query ) ,
index . searchAsync ( query )
] ) . then ( callback ) ;
Di dalam panggilan balik Promise.all()
Anda juga akan mendapatkan serangkaian hasil sebagai parameter pertama untuk setiap kueri yang Anda masukkan.
Saat menggunakan await
Anda dapat memprioritaskan pesanan (prioritaskan "tugas pertama selesai") dan menyelesaikan permintaan satu per satu dan hanya memproses subtugas secara paralel:
await index . searchAsync ( query ) ;
await index . searchAsync ( query ) ;
await index . searchAsync ( query ) ;
Sama untuk index.add()
, index.append()
, index.remove()
atau index.update()
. Di sini ada kasus khusus yang tidak dinonaktifkan oleh perpustakaan, namun Anda perlu mengingatnya saat menggunakan Pekerja.
Saat Anda memanggil versi "yang disinkronkan" pada indeks pekerja:
index . add ( doc ) ;
index . add ( doc ) ;
index . add ( doc ) ;
// contents aren't indexed yet,
// they just queued on the message channel
Tentu saja, Anda dapat melakukan itu namun perlu diingat bahwa thread utama tidak memiliki antrean tambahan untuk tugas pekerja terdistribusi. Menjalankan ini dalam loop yang panjang akan menembakkan konten secara besar-besaran ke saluran pesan melalui worker.postMessage()
secara internal. Untungnya browser dan Node.js akan menangani tugas masuk tersebut untuk Anda secara otomatis (selama tersedia RAM yang cukup). Saat menggunakan versi "yang disinkronkan" pada indeks pekerja, konten tidak diindeks satu baris di bawahnya, karena semua panggilan diperlakukan sebagai asinkron secara default.
Saat menambahkan/memperbarui/menghapus konten dalam jumlah besar ke indeks (atau frekuensi tinggi), disarankan untuk menggunakan versi async bersama dengan
async/await
untuk menjaga jejak memori rendah selama proses yang panjang.
Ekspor sedikit berubah. Ekspor sekarang terdiri dari beberapa bagian yang lebih kecil, bukan hanya satu bagian dalam jumlah besar. Anda harus meneruskan fungsi panggilan balik yang memiliki 2 argumen "kunci" dan "data". Fungsi panggilan balik ini dipanggil oleh masing-masing bagian, misalnya:
index . export ( function ( key , data ) {
// you need to store both the key and the data!
// e.g. use the key for the filename and save your data
localStorage . setItem ( key , data ) ;
} ) ;
Mengekspor data ke Penyimpanan lokal bukanlah praktik yang baik, tetapi jika ukuran tidak menjadi masalah, gunakanlah jika Anda mau. Ekspor terutama dilakukan untuk penggunaan di Node.js atau untuk menyimpan indeks yang ingin Anda delegasikan dari server ke klien.
Ukuran ekspor sesuai dengan konsumsi memori perpustakaan. Untuk mengurangi ukuran ekspor Anda harus menggunakan konfigurasi yang memiliki jejak memori lebih sedikit (gunakan tabel di bagian bawah untuk mendapatkan informasi tentang konfigurasi dan alokasi memorinya).
Ketika rutinitas penyimpanan Anda berjalan secara asinkron, Anda harus mengembalikan janji:
index . export ( function ( key , data ) {
return new Promise ( function ( resolve ) {
// do the saving as async
resolve ( ) ;
} ) ;
} ) ;
Anda tidak dapat mengekspor tabel tambahan untuk fitur "fastupdate". Tabel referensi ini ada dan ketika disimpan, tabel tersebut menjadi berseri dan menjadi terlalu besar. Lib akan menangani ini secara otomatis untuk Anda. Saat mengimpor data, indeks secara otomatis menonaktifkan "fastupdate".
Sebelum Anda dapat mengimpor data, Anda perlu membuat indeks terlebih dahulu. Untuk indeks dokumen, berikan deskriptor dokumen yang sama dengan yang Anda gunakan saat mengekspor data. Konfigurasi ini tidak disimpan dalam ekspor.
var index = new Index ( { ... } ) ;
Untuk mengimpor data cukup berikan kunci dan data:
index . import ( key , localStorage . getItem ( key ) ) ;
Anda perlu mengimpor setiap kunci! Jika tidak, indeks Anda tidak akan berfungsi. Anda perlu menyimpan kunci dari ekspor dan menggunakan kunci ini untuk mengimpor (urutan kunci dapat berbeda).
Ini hanya untuk demonstrasi dan tidak disarankan, karena Anda mungkin memiliki kunci lain di Penyimpanan lokal Anda yang tidak didukung sebagai impor:
var keys = Object . keys ( localStorage ) ;
for ( let i = 0 , key ; i < keys . length ; i ++ ) {
key = keys [ i ] ;
index . import ( key , localStorage . getItem ( key ) ) ;
}
Definisi khusus bahasa dibagi menjadi dua kelompok:
function(string):string[]
boolean
{string: string}
{string: string}
string[]
Charset berisi logika pengkodean, bahasanya berisi stemmer, filter stopword, dan pencocokan. Beberapa definisi bahasa dapat menggunakan encoder charset yang sama. Pemisahan ini juga memungkinkan Anda mengelola definisi bahasa yang berbeda untuk kasus penggunaan khusus (misalnya nama, kota, dialek/bahasa gaul, dll.).
Untuk mendeskripsikan sepenuhnya bahasa khusus dengan cepat, Anda harus menyampaikan:
const index = FlexSearch ( {
// mandatory:
encode : ( content ) => [ words ] ,
// optionally:
rtl : false ,
stemmer : { } ,
matcher : { } ,
filter : [ ]
} ) ;
Saat tidak meneruskan parameter, ia menggunakan skema latin:default
secara default.
Bidang | Kategori | Keterangan |
menyandi | rangkaian karakter | Fungsi pembuat enkode. Harus mengembalikan array kata-kata yang dipisahkan (atau string kosong). |
rtl | rangkaian karakter | Properti boolean yang menunjukkan pengkodean kanan ke kiri. |
menyaring | bahasa | Filter juga dikenal sebagai "stopwords", filter ini sepenuhnya menyaring kata-kata agar tidak diindeks. |
batang | bahasa | Stemmer menghilangkan akhiran kata dan merupakan semacam "normalisasi parsial". Akhiran kata baru saja dicocokkan jika panjang kata lebih besar dari bagian yang cocok. |
pencocokan | bahasa | Matcher menggantikan semua kemunculan string tertentu terlepas dari posisinya dan juga merupakan semacam "normalisasi parsial". |
Cara paling sederhana untuk menetapkan pengkodean khusus charset/bahasa melalui modul adalah:
import charset from "./dist/module/lang/latin/advanced.js" ;
import lang from "./dist/module/lang/en.js" ;
const index = FlexSearch ( {
charset : charset ,
lang : lang
} ) ;
Cukup impor ekspor default untuk setiap modul dan tetapkan sesuai dengan itu.
Contoh lengkap yang memenuhi syarat dari atas adalah:
import { encode , rtl } from "./dist/module/lang/latin/advanced.js" ;
import { stemmer , filter , matcher } from "./dist/module/lang/en.js" ;
const index = FlexSearch ( {
encode : encode ,
rtl : rtl ,
stemmer : stemmer ,
matcher : matcher ,
filter : filter
} ) ;
Contoh di atas adalah antarmuka standar yang setidaknya diekspor dari setiap charset/bahasa.
Anda juga dapat menentukan encoder secara langsung dan meninggalkan semua opsi lainnya:
import simple from "./dist/module/lang/latin/simple.js" ;
const index = FlexSearch ( {
encode : simple
} ) ;
Anda dapat menetapkan rangkaian karakter dengan meneruskan rangkaian karakter tersebut selama inisialisasi, misalnya charset: "latin"
untuk encoder charset default atau charset: "latin:soundex"
untuk varian encoder.
Definisi bahasa (terutama pencocokan) juga dapat digunakan untuk menormalkan dialek dan bahasa gaul suatu bahasa tertentu.
Anda perlu menyediakan rangkaian karakter dan/atau definisi bahasa dengan:
flexsearch.bundle.js
secara default, tetapi tidak ada definisi khusus bahasa yang disertakan/dist/lang/
(file mengacu pada bahasa, folder adalah rangkaian karakter)Saat memuat paket bahasa, pastikan perpustakaan telah dimuat sebelumnya:
< script src =" dist/flexsearch.light.js " > </ script >
< script src =" dist/lang/latin/default.min.js " > </ script >
< script src =" dist/lang/en.min.js " > </ script >
Saat menggunakan versi "bundel" lengkap, encoder Latin bawaan sudah disertakan dan Anda hanya perlu memuat file bahasa:
< script src =" dist/flexsearch.bundle.js " > </ script >
< script src =" dist/lang/en.min.js " > </ script >
Karena Anda memuat paket sebagai paket eksternal (non-ES6-modules), Anda harus menginisialisasi dengan pintasan:
const index = FlexSearch ( {
charset : "latin:soundex" ,
lang : "en"
} ) ;
Gunakan notasi
charset:variant
untuk menetapkan charset dan variannya. Saat hanya melewati charset tanpa varian akan secara otomatis diselesaikan sebagaicharset:default
.
Anda juga dapat mengganti definisi yang ada, misalnya:
const index = FlexSearch ( {
charset : "latin" ,
lang : "en" ,
matcher : { }
} ) ;
Definisi lulus tidak akan memperluas definisi default, mereka akan menggantikannya.
Ketika Anda ingin memperluas definisi, cukup buat file bahasa baru dan masukkan semua logika.
Cukup lurus ke depan saat menggunakan varian enkoder:
< script src =" dist/flexsearch.light.js " > </ script >
< script src =" dist/lang/latin/advanced.min.js " > </ script >
< script src =" dist/lang/latin/extra.min.js " > </ script >
< script src =" dist/lang/en.min.js " > </ script >
Saat menggunakan versi "bundel" lengkap, encoder Latin bawaan sudah disertakan dan Anda hanya perlu memuat file bahasa:
< script src =" dist/flexsearch.bundle.js " > </ script >
< script src =" dist/lang/en.min.js " > </ script >
const index_advanced = FlexSearch ( {
charset : "latin:advanced"
} ) ;
const index_extra = FlexSearch ( {
charset : "latin:extra"
} ) ;
Dalam FlexSearch Anda tidak dapat memberikan tokenizer parsial Anda sendiri, karena ini merupakan ketergantungan langsung ke unit inti. Tokenizer bawaan dari FlexSearch membagi setiap kata menjadi fragmen dengan pola yang berbeda:
Ini adalah pipa default yang disediakan oleh FlexSearch:
Pada awalnya perhatikan pipa default di src/common.js
. Ini sangat sederhana dan lurus ke depan. Pipa akan diproses sebagai semacam inversi kontrol, implementasi enkoder akhir harus menangani charset dan juga transformasi spesifik bahasa. Solusi ini telah tersisa dari banyak tes.
Menyuntikkan pipa default oleh misalnya:
this . pipeline (
/* string: */ str . toLowerCase ( ) ,
/* normalize: */ false ,
/* split: */ split ,
/* collapse: */ false
) ;
Gunakan skema pipa dari atas untuk memahami iterasi dan perbedaan pra-penyodean dan pasca-pengodean. Stemmer dan pencocokan perlu diterapkan setelah normalisasi charset tetapi sebelum transformasi bahasa, filter juga.
Berikut ini adalah contoh yang baik untuk memperpanjang pipa: src/lang/latin/extra.js
→ src/lang/latin/advanced.js
→ src/lang/latin/simple.js
.
Cari bahasa Anda di src/lang/
, jika ada Anda dapat memperpanjang atau memberikan varian (seperti dialek/bahasa gaul). Jika bahasa tidak ada membuat file baru dan periksa apakah salah satu charset yang ada (misalnya Latin) cocok dengan bahasa Anda. Ketika tidak ada charset, Anda perlu memberikan charset sebagai basis untuk bahasa.
Charset baru harus menyediakan setidaknya:
encode
fungsi yang menormalkan charset dari konten teks yang disahkan (hapus karakter khusus, transformasi lingual, dll.) Dan mengembalikan array kata yang terpisah . Juga filter stemmer, pencocokan atau stopword perlu diterapkan di sini. Ketika bahasa tidak memiliki kata -kata, pastikan untuk memberikan sesuatu yang serupa, misalnya setiap tanda Cina juga bisa menjadi "kata". Jangan mengembalikan seluruh konten teks tanpa split.rtl
bendera boolean yang menunjukkan penyandian kanan-ke-kiriPada dasarnya charset hanya perlu untuk menyediakan fungsi encoder bersama dengan indikator untuk pengkodean kanan-ke-kiri:
export function encode ( str ) { return [ str ] }
export const rtl = false ;
String referensi: "Björn-Phillipp Mayer"
Pertanyaan | bawaan | sederhana | canggih | tambahan |
Björn | Ya | Ya | Ya | Ya |
Björ | Ya | Ya | Ya | Ya |
bjorn | TIDAK | Ya | Ya | Ya |
bjoern | TIDAK | TIDAK | Ya | Ya |
Philipp | TIDAK | TIDAK | Ya | Ya |
filip | TIDAK | TIDAK | Ya | Ya |
Björnphillip | TIDAK | Ya | Ya | Ya |
Meier | TIDAK | TIDAK | Ya | Ya |
Björn Meier | TIDAK | TIDAK | Ya | Ya |
Meier Fhilip | TIDAK | TIDAK | Ya | Ya |
Byorn Mair | TIDAK | TIDAK | TIDAK | Ya |
(positif palsu) | TIDAK | TIDAK | TIDAK | Ya |
Buku "Gulliver's Travels Swift Jonathan 1726" sepenuhnya diindeks untuk contoh di bawah ini.
Pengaturan bermakna yang paling dioptimalkan memori akan mengalokasikan hanya 1,2 MB untuk seluruh buku yang diindeks! Ini mungkin jejak memori paling kecil yang akan Anda dapatkan dari perpustakaan pencarian.
import { encode } from "./lang/latin/extra.js" ;
index = new Index ( {
encode : encode ,
tokenize : "strict" ,
optimize : true ,
resolution : 1 ,
minlength : 3 ,
fastupdate : false ,
context : false
} ) ;
Buku "Gulliver's Travels" (Swift Jonathan 1726) sepenuhnya diindeks untuk tes ini:
Secara default indeks leksikal sangat kecil:
depth: 0, bidirectional: 0, resolution: 3, minlength: 0
=> 2.1 MB
Resolusi yang lebih tinggi akan meningkatkan alokasi memori:
depth: 0, bidirectional: 0, resolution: 9, minlength: 0
=> 2.9 MB
Menggunakan indeks kontekstual akan meningkatkan alokasi memori:
depth: 1, bidirectional: 0, resolution: 9, minlength: 0
=> 12,5 MB
Kedalaman kontekstual yang lebih tinggi akan meningkatkan alokasi memori:
depth: 2, bidirectional: 0, resolution: 9, minlength: 0
=> 21,5 MB
Minlength yang lebih tinggi akan mengurangi alokasi memori:
depth: 2, bidirectional: 0, resolution: 9, minlength: 3
=> 19.0 MB
Menggunakan dua arah akan mengurangi alokasi memori:
depth: 2, bidirectional: 1, resolution: 9, minlength: 3
=> 17.9 MB
Aktifkan opsi "FastUpdate" akan meningkatkan alokasi memori:
depth: 2, bidirectional: 1, resolution: 9, minlength: 3
=> 6.3 Mb
Setiap perpustakaan pencarian terus -menerus bersaing dengan 4 properti ini:
FlexSearch memberi Anda banyak parameter yang dapat Anda gunakan untuk menyesuaikan keseimbangan optimal untuk kasus penggunaan spesifik Anda.
Pengubah | Dampak Memori * | Dampak Kinerja ** | Dampak Pencocokan ** | Dampak mencetak gol ** |
resolusi | +1 (per level) | +1 (per level) | 0 | +2 (per level) |
kedalaman | +4 (per level) | -1 (per level) | -10 + kedalaman | +10 |
Minlength | -2 (per level) | +2 (per level) | -3 (per level) | +2 (per level) |
dua arah | -2 | 0 | +3 | -1 |
fastupdate | +1 | +10 (perbarui, hapus) | 0 | 0 |
Optimalkan: Benar | -7 | -1 | 0 | -3 |
Encoder: "Icase" | 0 | 0 | 0 | 0 |
Encoder: "Sederhana" | -2 | -1 | +2 | 0 |
Encoder: "Advanced" | -3 | -2 | +4 | 0 |
Encoder: "Extra" | -5 | -5 | +6 | 0 |
Encoder: "Soundex" | -6 | -2 | +8 | 0 |
Tokenize: "ketat" | 0 | 0 | 0 | 0 |
Tokenize: "Maju" | +3 | -2 | +5 | 0 |
Tokenize: "Reverse" | +5 | -4 | +7 | 0 |
Tokenize: "Full" | +8 | -5 | +10 | 0 |
Indeks Dokumen | +3 (per bidang) | -1 (per bidang) | 0 | 0 |
Tag dokumen | +1 (per tag) | -1 (per tag) | 0 | 0 |
Toko: Benar | +5 (per dokumen) | 0 | 0 | 0 |
Toko: [Fields] | +1 (per bidang) | 0 | 0 | 0 |
Cache: Benar | +10 | +10 | 0 | 0 |
Cache: 100 | +1 | +9 | 0 | 0 |
Jenis ID: Angka | 0 | 0 | 0 | 0 |
Jenis ID: String | +3 | -3 | 0 | 0 |
memory
(optimalisasi primer untuk memori)performance
(Optimalkan Primer untuk Kinerja)match
(optimalisasi utama untuk pencocokan)score
(optimalkan primer untuk penilaian)default
(profil seimbang default)Profil ini mencakup kasus penggunaan standar. Disarankan untuk menerapkan konfigurasi khusus alih -alih menggunakan profil untuk mendapatkan yang terbaik untuk situasi Anda. Setiap profil dapat dioptimalkan lebih lanjut untuk tugas spesifiknya, misalnya konfigurasi yang dioptimalkan dengan kinerja ekstrem atau memori ekstrem dan sebagainya.
Anda dapat melewati preset selama pembuatan/inisialisasi indeks.
Disarankan untuk menggunakan nilai ID numerik sebagai referensi saat menambahkan konten ke indeks. Panjang byte ID yang ditularkan mempengaruhi konsumsi memori secara signifikan. Jika ini tidak mungkin, Anda harus mempertimbangkan untuk menggunakan tabel indeks dan memetakan ID dengan indeks, ini menjadi penting terutama ketika menggunakan indeks kontekstual pada sejumlah besar konten.
Kapanpun Anda bisa, cobalah membagi konten dengan kategori dan menambahkannya ke indeksnya sendiri, misalnya:
var action = new FlexSearch ( ) ;
var adventure = new FlexSearch ( ) ;
var comedy = new FlexSearch ( ) ;
Dengan cara ini Anda juga dapat memberikan pengaturan yang berbeda untuk setiap kategori. Ini sebenarnya cara tercepat untuk melakukan pencarian fuzzy.
Untuk membuat solusi ini lebih dapat diperpanjang, Anda dapat menggunakan penolong pendek:
var index = { } ;
function add ( id , cat , content ) {
( index [ cat ] || (
index [ cat ] = new FlexSearch
) ) . add ( id , content ) ;
}
function search ( cat , query ) {
return index [ cat ] ?
index [ cat ] . search ( query ) : [ ] ;
}
Tambahkan konten ke indeks:
add ( 1 , "action" , "Movie Title" ) ;
add ( 2 , "adventure" , "Movie Title" ) ;
add ( 3 , "comedy" , "Movie Title" ) ;
Lakukan pertanyaan:
var results = search ( "action" , "movie title" ) ; // --> [1]
Indeks split berdasarkan kategori meningkatkan kinerja secara signifikan.
Hak Cipta 2018-2023 Thomas Wilkerling, Dipandu oleh NextApps Gmbh
Dirilis di bawah lisensi Apache 2.0