دعونا نناقش الإصدار 0.8 من FlexSearch القادم هنا: #415
البداية الأساسية • مرجع API • فهارس المستندات • استخدام العامل • سجل التغيير
يمكنك مساعدتي من خلال التبرع الشخصي للإبقاء على هذا المشروع على قيد الحياة وكذلك تقديم كل المساهمة لحل احتياجاتك.
العمليات المضادة ذ.م.م
عندما يتعلق الأمر بسرعة البحث الأولية، يتفوق FlexSearch في الأداء على كل مكتبة بحث موجودة ويوفر أيضًا إمكانات بحث مرنة مثل البحث متعدد المجالات أو التحويلات الصوتية أو المطابقة الجزئية.
اعتمادًا على الخيارات المستخدمة، فإنه يوفر أيضًا الفهرس الأكثر كفاءة في الذاكرة. تقدم FlexSearch خوارزمية تسجيل جديدة تسمى "الفهرس السياقي" استنادًا إلى بنية القاموس المعجمي التي تم تسجيلها مسبقًا والتي تنفذ بالفعل استعلامات أسرع بما يصل إلى 1,000,000 مرة مقارنة بالمكتبات الأخرى. يوفر لك FlexSearch أيضًا نموذج معالجة غير متزامن غير محظور بالإضافة إلى عمال الويب لإجراء أي تحديثات أو استعلامات على الفهرس بالتوازي من خلال سلاسل رسائل متوازنة مخصصة.
المنصات المدعومة:
مقارنة المكتبة "رحلات جاليفر":
الإضافات (المشاريع الخارجية):
يبني | ملف | CDN |
flexsearch.bundle.js | تحميل | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.bundle.js |
flexsearch.light.js | تحميل | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.light.js |
flexsearch.compact.js | تحميل | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.compact.js |
flexsearch.es5.js * | تحميل | https://rawcdn.githack.com/nextapps-de/flexsearch/0.7.31/dist/flexsearch.es5.js |
وحدات ES6 | تحميل | المجلد /dist/module/ الخاص بمستودع Github هذا |
* تتضمن الحزمة "flexsearch.es5.js" ملفات متعددة لدعم EcmaScript 5.
npm install flexsearch
تتضمن حزمة Node.js كافة الميزات الموجودة في
flexsearch.bundle.js
.
ميزة | flexsearch.bundle.js | flexsearch.compact.js | flexsearch.light.js |
الإعدادات المسبقة | ✓ | ✓ | - |
بحث غير متزامن | ✓ | ✓ | - |
العمال (الويب + Node.js) | ✓ | - | - |
الفهارس السياقية | ✓ | ✓ | ✓ |
فهرسة المستندات (البحث الميداني) | ✓ | ✓ | - |
مخزن المستندات | ✓ | ✓ | - |
المطابقة الجزئية | ✓ | ✓ | ✓ |
تسجيل الملاءمة | ✓ | ✓ | ✓ |
ذاكرة التخزين المؤقت المتوازنة تلقائيًا حسب الشعبية | ✓ | - | - |
العلامات | ✓ | - | - |
اقتراحات | ✓ | ✓ | - |
المطابقة الصوتية | ✓ | ✓ | - |
مجموعة أحرف/لغة قابلة للتخصيص (المطابق، المشفر، أداة الرمز، Stemmer، المرشح، الانقسام، RTL) | ✓ | ✓ | ✓ |
فهارس التصدير/الاستيراد | ✓ | - | - |
حجم الملف (gzip) | 6.8 كيلو بايت | 5.3 كيلو بايت | 2.9 كيلو بايت |
إجراء المقارنة: معيار الأداء "رحلات جاليفر"
التشغيل بالثواني الأعلى هو الأفضل، باستثناء اختبار "الذاكرة" الذي يكون فيه أقل أفضل.
رتبة | مكتبة | ذاكرة | استعلام (فصل مفرد) | استعلام (متعدد المصطلحات) | استعلام (طويل) | الاستعلام (المغفلين) | الاستعلام (غير موجود) |
1 | فليكسسيرش | 17 | 7084129 | 1586856 | 511585 | 2017142 | 3202006 |
2 | JSii | 27 | 6564 | 158149 | 61290 | 95098 | 534109 |
3 | وايد | 424 | 20471 | 78780 | 16693 | 225824 | 213754 |
4 | بحث شبيبة | 193 | 8221 | 64034 | 10377 | 95830 | 167605 |
5 | Elasticlunr.js | 646 | 5412 | 7573 | 2865 | 23786 | 13982 |
6 | البحث بالجملة | 1021 | 3069 | 3141 | 3333 | 3265 | 21825569 |
7 | بحث صغير | 24348 | 4406 | 10945 | 72 | 39989 | 17624 |
8 | bm25 | 15719 | 1429 | 789 | 366 | 884 | 1823 |
9 | Lunr.js | 2219 | 255 | 271 | 272 | 266 | 267 |
10 | بحث غامض | 157373 | 53 | 38 | 15 | 32 | 43 |
11 | الصمامات | 7641904 | 6 | 2 | 1 | 2 | 3 |
هناك 3 أنواع من الفهارس:
Index
عبارة عن فهرس مسطح عالي الأداء يقوم بتخزين أزواج محتوى المعرفات.Worker
/ WorkerIndex
أيضًا فهرسًا مسطحًا يقوم بتخزين أزواج محتوى المعرفات ولكنه يعمل في الخلفية كسلسلة عاملة مخصصة.Document
عبارة عن فهرس متعدد الحقول يمكنه تخزين مستندات JSON المعقدة (يمكن أن يوجد أيضًا فهارس عاملة).ربما يحتاج معظمكم إلى واحد منهم فقط وفقًا للسيناريو الخاص بك.
< 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 >
أو عبر CDN:
< script src =" https://cdn.jsdelivr.net/gh/nextapps-de/[email protected]/dist/flexsearch.bundle.min.js " > </ script >
أيه إم دي / كومون جي إس:
var FlexSearch = require ( "./node_modules/flexsearch/dist/flexsearch.bundle.min.js" ) ;
npm install flexsearch
في التعليمات البرمجية الخاصة بك تشمل ما يلي:
const { Index , Document , Worker } = require ( "flexsearch" ) ;
const index = new Index ( options ) ;
const document = new Document ( options ) ;
const worker = new Worker ( options ) ;
أو:
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
من النوع Index
ولا يرث من النوع Document
. لذلك، يعمل WorkerIndex بشكل أساسي مثل مؤشر FlexSearch القياسي. يجب تمكين دعم العمال في المستندات بمجرد تمرير الخيار المناسب أثناء الإنشاء { worker: true }
.
يتم التعامل مع كل طريقة يتم استدعاؤها في فهرس
Worker
على أنها غير متزامنة. سوف تحصل علىPromise
أو يمكنك توفير وظيفة رد الاتصال كمعلمة أخيرة بدلاً من ذلك.
الأساليب العالمية:
طرق الفهرس:
طرق مؤشر العامل:
طرق التوثيق:
* لكل من هذه الطرق يوجد معادل غير متزامن:
الإصدار غير المتزامن:
سوف تُرجع الأساليب غير المتزامنة Promise
، وبدلاً من ذلك يمكنك تمرير وظيفة رد الاتصال كمعلمة أخيرة.
تكون طرق export
import
أيضًا غير متزامنة دائمًا وكذلك كل طريقة تستدعيها في فهرس يستند إلى العامل.
FlexSearch قابل للتخصيص بدرجة كبيرة. يمكن أن يؤدي استخدام الخيارات الصحيحة إلى تحسين نتائجك بالإضافة إلى الاقتصاد في الذاكرة ووقت الاستعلام.
خيار | قيم | وصف | تقصير |
محددة مسبقا | "ذاكرة" "أداء" "مباراة" "نتيجة" "تقصير" | ملف تعريف التكوين كاختصار أو كقاعدة لإعداداتك المخصصة. | "تقصير" |
رمز مميز | "حازم" "إلى الأمام" "يعكس" "ممتلىء" | وضع الفهرسة (الرمز المميز). اختر أحد العناصر المضمنة أو قم بتمرير وظيفة رمزية مخصصة. | "حازم" |
مخبأ | منطقية رقم | تمكين/تعطيل و/أو تعيين سعة الإدخالات المخزنة مؤقتًا. عند تمرير رقم كحد أقصى ، تقوم ذاكرة التخزين المؤقت تلقائيًا بموازنة الإدخالات المخزنة المتعلقة بشعبيتها . ملحوظة: عند استخدام "صحيح" فقط، فإن ذاكرة التخزين المؤقت ليس لها حدود والنمو غير محدود. | خطأ شنيع |
دقة | رقم | يضبط دقة التسجيل (الافتراضي: 9). | 9 |
سياق | منطقية خيارات السياق | تمكين/تعطيل الفهرسة السياقية. عند تمرير "صحيح" كقيمة، فإنه سيأخذ القيم الافتراضية للسياق. | خطأ شنيع |
تحسين | منطقية | عند تمكينه، فإنه يستخدم تدفق مكدس محسّن للذاكرة للفهرس. | حقيقي |
يعزز | دالة (arr، str، int) => float | وظيفة تعزيز مخصصة تستخدم عند فهرسة المحتويات إلى الفهرس. تحتوي الوظيفة على هذا التوقيع: Function(words[], term, index) => Float . يحتوي على 3 معلمات حيث تحصل على مصفوفة من كل الكلمات والمصطلح الحالي والفهرس الحالي حيث يتم وضع المصطلح في مصفوفة الكلمات. يمكنك تطبيق حساباتك الخاصة، على سبيل المثال، تكرارات المصطلح وإرجاع هذا العامل (<1 يعني تقليل الملاءمة، >1 يعني زيادة الملاءمة).ملحوظة: هذه الميزة محدودة حاليًا باستخدام الرمز المميز "الصارم" فقط. | باطل |
الخيارات والتشفير الخاص باللغة: | |||
مجموعة محارف | حمولة مجموعة الأحرف سلسلة (مفتاح) | قم بتوفير حمولة مجموعة أحرف مخصصة أو قم بتمرير أحد مفاتيح مجموعات الأحرف المضمنة. | "اللاتينية" |
لغة | حمولة اللغة سلسلة (مفتاح) | توفير حمولة لغة مخصصة أو تمرير علامة اختزال اللغة (ISO-3166) للغات المضمنة. | باطل |
ترميز | خطأ شنيع "تقصير" "بسيط" "توازن" "متقدم" "إضافي" الدالة(شارع) => [كلمات] | نوع الترميز. اختر أحد العناصر المضمنة أو قم بتمرير وظيفة ترميز مخصصة. | "تقصير" |
ستيمر | خطأ شنيع خيط وظيفة | خطأ شنيع | |
فلتر | خطأ شنيع خيط وظيفة | خطأ شنيع | |
المطابق | خطأ شنيع خيط وظيفة | خطأ شنيع | |
خيارات إضافية لفهارس المستندات: | |||
عامل | منطقية | تمكين/تعطيل وتعيين عدد سلاسل العمليات العاملة. | خطأ شنيع |
وثيقة | واصف الوثيقة | يتضمن تعريفات لفهرس المستندات وتخزينها. |
خيار | قيم | وصف | تقصير |
دقة | رقم | يضبط دقة التسجيل للسياق (الافتراضي: 1). | 1 |
عمق | خطأ شنيع رقم | تمكين/تعطيل الفهرسة السياقية وكذلك تعيين المسافة السياقية ذات الصلة. العمق هو الحد الأقصى لعدد الكلمات/الرموز المميزة التي يمكن اعتبارها ذات صلة بالمصطلح. | 1 |
ثنائي الاتجاه | منطقية | يحدد نتيجة البحث ثنائية الاتجاه. إذا تم تمكينه وكان النص المصدر يحتوي على "قبعة حمراء"، فسيتم العثور عليه للاستعلامات "قبعة حمراء" و"قبعة حمراء". | حقيقي |
خيار | قيم | وصف | تقصير |
بطاقة تعريف | خيط | "بطاقة تعريف"" | |
علامة | خطأ شنيع خيط | "علامة" | |
فِهرِس | خيط صفيف <سلسلة> صفيف <كائن> | ||
محل | منطقية خيط صفيف <سلسلة> | خطأ شنيع |
خيار | قيم | وصف | تقصير |
ينقسم | خطأ شنيع RegExp خيط | قاعدة تقسيم الكلمات عند استخدام أداة رمزية غير مخصصة (مدمجة، على سبيل المثال "إعادة التوجيه"). استخدم سلسلة/حرف أو استخدم تعبيرًا عاديًا (الافتراضي: /W+/ ). | /[W_]+/ |
rtl | منطقية | تمكين التشفير من اليمين إلى اليسار. | خطأ شنيع |
ترميز | الدالة(شارع) => [كلمات] | وظيفة الترميز المخصصة. | /lang/latin/default.js |
خيار | قيم | وصف |
ستيمر | خطأ شنيع خيط وظيفة | تعطيل أو تمرير علامة اختزال اللغة (ISO-3166) أو كائن مخصص. |
فلتر | خطأ شنيع خيط وظيفة | تعطيل أو تمرير علامة اختزال اللغة (ISO-3166) أو مصفوفة مخصصة. |
المطابق | خطأ شنيع خيط وظيفة | تعطيل أو تمرير علامة اختزال اللغة (ISO-3166) أو مصفوفة مخصصة. |
خيار | قيم | وصف | تقصير |
حد | رقم | يضبط حدود النتائج. | 100 |
إزاحة | رقم | تطبيق الإزاحة (تخطي العناصر). | 0 |
يقترح | منطقية | تمكين الاقتراحات في النتائج. | خطأ شنيع |
خيار | قيم | وصف | تقصير |
فِهرِس | خيط صفيف <سلسلة> صفيف <كائن> | يضبط حقول الوثيقة التي يجب البحث فيها. عندما لا يتم تعيين أي حقل، سيتم البحث في جميع الحقول. يتم أيضًا دعم الخيارات المخصصة لكل حقل. | |
علامة | خيط صفيف <سلسلة> | يضبط حقول الوثيقة التي يجب البحث فيها. عندما لا يتم تعيين أي حقل، سيتم البحث في جميع الحقول. يتم أيضًا دعم الخيارات المخصصة لكل حقل. | خطأ شنيع |
إثراء | منطقية | إثراء المعرفات من النتائج بالوثائق المقابلة. | خطأ شنيع |
منطقي | "و" "أو" | يضبط العامل المنطقي المستخدم عند البحث في حقول أو علامات متعددة. | "أو" |
يؤثر Tokenizer على الذاكرة المطلوبة أيضًا مثل وقت الاستعلام ومرونة التطابقات الجزئية. حاول اختيار الجزء العلوي من هذه الرموز المميزة التي تناسب احتياجاتك:
خيار | وصف | مثال | عامل الذاكرة (ن = طول الكلمة) |
"حازم" | فهرس الكلمات بأكملها | foobar | * 1 |
"إلى الأمام" | فهرسة الكلمات بشكل متزايد في الاتجاه الأمامي | fo obarfoob آر | * ن |
"يعكس" | فهرسة الكلمات بشكل متزايد في كلا الاتجاهين | فوب ar fo obar | * 2 ن - 1 |
"ممتلىء" | فهرسة كل مجموعة ممكنة | فو oba رو oob | * ن * (ن - 1) |
يؤثر التشفير على الذاكرة المطلوبة أيضًا مثل وقت الاستعلام والمطابقات الصوتية. حاول اختيار أعلى برامج التشفير هذه التي تناسب احتياجاتك، أو قم بتمرير برنامج تشفير مخصص:
خيار | وصف | إيجابيات كاذبة | ضغط |
خطأ شنيع | قم بإيقاف تشغيل الترميز | لا | 0% |
"تقصير" | ترميز حساس لحالة الأحرف | لا | 0% |
"بسيط" | ترميز حساس لحالة الأحرف تطبيع محارف | لا | ~ 3% |
"توازن" | ترميز حساس لحالة الأحرف تطبيع محارف التحولات الحرفية | لا | ~ 30% |
"متقدم" | ترميز حساس لحالة الأحرف تطبيع محارف التحولات الحرفية التطبيع الصوتي | لا | ~ 40% |
"إضافي" | ترميز حساس لحالة الأحرف تطبيع محارف التحولات الحرفية التطبيع الصوتي تحويلات ساوندكس | نعم | ~ 65% |
وظيفة() | تمرير ترميز مخصص عبر الدالة(سلسلة):[words] |
var index = new Index ( ) ;
قم بإنشاء فهرس جديد واختيار أحد الإعدادات المسبقة:
var index = new Index ( "performance" ) ;
قم بإنشاء فهرس جديد بخيارات مخصصة:
var index = new Index ( {
charset : "latin:extra" ,
tokenize : "reverse" ,
resolution : 9
} ) ;
أنشئ فهرسًا جديدًا وقم بتوسيع الإعداد المسبق بخيارات مخصصة:
var index = new FlexSearch ( {
preset : "memory" ,
tokenize : "forward" ,
resolution : 5
} ) ;
شاهد جميع الخيارات المخصصة المتاحة.
كل محتوى يجب إضافته إلى الفهرس يحتاج إلى معرف. عندما لا يحتوي المحتوى الخاص بك على معرف، فأنت بحاجة إلى إنشاء واحد عن طريق تمرير فهرس أو عدد أو أي شيء آخر كمعرف (يوصى بشدة باستخدام قيمة من نوع number
). هذه المعرفات هي مراجع فريدة لمحتوى معين. يعد هذا أمرًا مهمًا عند تحديث المحتوى أو إضافته من خلال المعرفات الموجودة. عندما لا يكون الرجوع إلى مصدر قلق، يمكنك ببساطة استخدام شيء بسيط مثل count++
.
فِهرِس. إضافة (معرف، سلسلة)
index . add ( 0 , "John Doe" ) ;
فِهرِس. بحث (سلسلة | خيارات، <limit>، <options>)
index . search ( "John" ) ;
الحد من النتيجة:
index . search ( "John" , 10 ) ;
يمكنك التحقق مما إذا كان المعرف قد تمت فهرسته بالفعل من خلال:
if ( index . contain ( 1 ) ) {
console . log ( "ID is already in index" ) ;
}
يمكنك استدعاء كل أسلوب في نسخته غير المتزامنة، على سبيل المثال index.addAsync
أو index.searchAsync
.
يمكنك تعيين عمليات رد اتصال لكل وظيفة غير متزامنة:
index . addAsync ( id , content , function ( ) {
console . log ( "Task Done" ) ;
} ) ;
index . searchAsync ( query , function ( result ) {
console . log ( "Results: " , result ) ;
} ) ;
أو لا تمرر وظيفة رد اتصال وتستعيد Promise
بدلاً من ذلك:
index . addAsync ( id , content ) . then ( function ( ) {
console . log ( "Task Done" ) ;
} ) ;
index . searchAsync ( query ) . then ( function ( result ) {
console . log ( "Results: " , result ) ;
} ) ;
أو استخدم async
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 ) ;
}
يمكنك إلحاق محتويات بفهرس موجود مثل:
index . append ( id , content ) ;
لن يؤدي هذا إلى استبدال المحتويات القديمة المفهرسة كما سيحدث عند تنفيذ index.update(id, content)
. ضع في اعتبارك أن index.add(id, content)
سيقوم أيضًا بإجراء "تحديث" أسفل الغطاء عندما تتم فهرسة المعرف بالفعل.
سيكون للمحتويات الملحقة سياقها الخاص وأيضًا resolution
كاملة خاصة بها. لذلك، لا يتم تجميع الملاءمة ولكنها تحصل على سياقها الخاص.
ولنأخذ هذا المثال:
index . add ( 0 , "some index" ) ;
index . append ( 0 , "some appended content" ) ;
index . add ( 1 , "some text" ) ;
index . append ( 1 , "index appended content" ) ;
عند الاستعلام عن index.search("index")
فإنك سوف تحصل على معرف الفهرس 1 كأول إدخال في النتيجة، لأن السياق يبدأ من الصفر للبيانات الملحقة (غير مكدس في السياق القديم) وهنا "الفهرس " هو المصطلح الأول .
إذا كنت لا تريد هذا السلوك، فاستخدم فقط index.add(id, content)
القياسي وقم بتوفير كامل المحتوى.
فِهرِس. التحديث (المعرف، السلسلة)
index . update ( 0 , "Max Miller" ) ;
فِهرِس. إزالة (المعرف)
index . remove ( 0 ) ;
يقوم الرمز المميز بتقسيم الكلمات/المصطلحات إلى مكونات أو أجزاء.
تحديد رمز مميز خاص أثناء الإنشاء/التهيئة:
var index = new FlexSearch ( {
tokenize : function ( str ) {
return str . split ( / s-/ / g ) ;
}
} ) ;
تحصل وظيفة الرمز المميز على سلسلة كمعلمة ويجب عليها إرجاع مجموعة من السلاسل التي تمثل كلمة أو مصطلحًا. في بعض اللغات، يكون كل حرف عبارة عن مصطلح ولا يتم فصله بمسافات بيضاء.
Stemmer: عدة طفرات لغوية لنفس الكلمة (مثل "تشغيل" و"تشغيل")
التصفية: قائمة سوداء بالكلمات التي سيتم تصفيتها من الفهرسة على الإطلاق (على سبيل المثال "و" أو "إلى" أو "يكون")
قم بتعيين عنصر أساسي أو عامل تصفية مخصص أثناء الإنشاء/التهيئة:
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"
]
} ) ;
استخدام مرشح مخصص، على سبيل المثال:
var index = new FlexSearch ( {
filter : function ( value ) {
// just add values with length > 1 to the index
return value . length > 1 ;
}
} ) ;
أو قم بتعيين Stemmer/filters عالميًا للغة:
يتم تمرير Stemmer ككائن (زوج قيمة المفتاح)، وتصفية كمصفوفة.
FlexSearch . registerLanguage ( "us" , {
stemmer : { /* ... */ } ,
filter : [ /* ... */ ]
} ) ;
أو استخدم بعض العناصر أو عوامل التصفية المحددة مسبقًا للغاتك المفضلة:
< 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 >
...
يمكنك الآن تعيين عنصر أساسي مضمن أثناء الإنشاء/التهيئة:
var index_en = new FlexSearch . Index ( {
language : "en"
} ) ;
var index_de = new FlexSearch . Index ( {
language : "de"
} ) ;
في Node.js تتوفر جميع ملفات حزم اللغات المضمنة:
const { Index } = require ( "flexsearch" ) ;
var index_en = new Index ( {
language : "en"
} ) ;
اضبط الرمز المميز على الأقل على "عكسي" أو "ممتلئ" عند استخدام RTL.
ما عليك سوى تعيين الحقل "rtl" على "صحيح " واستخدام رمز مميز متوافق:
var index = new Index ( {
encode : str => str . toLowerCase ( ) . split ( / [^a-z]+ / ) ,
tokenize : "reverse" ,
rtl : true
} ) ;
قم بتعيين رمز مميز يناسب احتياجاتك، على سبيل المثال:
var index = FlexSearch . create ( {
encode : str => str . replace ( / [x00-x7F] / g , "" ) . split ( "" )
} ) ;
يمكنك أيضًا تمرير وظيفة تشفير مخصصة لتطبيق بعض التحولات اللغوية.
index . add ( 0 , "一个单词" ) ;
var results = index . search ( "单词" ) ;
بافتراض أن وثيقتنا تحتوي على بنية بيانات مثل هذا:
{
"id" : 0 ,
"content" : " some text "
}
بناء الجملة القديم FlexSearch v0.6.3 ( لم يعد مدعومًا بعد الآن! ):
const index = new Document ( {
doc : {
id : "id" ,
field : [ "content" ]
}
} ) ;
لقد تغير واصف المستند قليلاً، ولم يعد هناك فرع
field
بعد الآن، وبدلاً من ذلك قم فقط بتطبيق مستوى أعلى واحد، لذلك يصبحkey
عضوًا رئيسيًا في الخيارات.
بالنسبة للصيغة الجديدة، تمت إعادة تسمية الحقل "doc" إلى document
وتمت إعادة تسمية الحقل "field" إلى index
:
const index = new Document ( {
document : {
id : "id" ,
index : [ "content" ]
}
} ) ;
index . add ( {
id : 0 ,
content : "some text"
} ) ;
يصف id
الحقل المكان الذي يوجد فيه المعرف أو المفتاح الفريد داخل مستنداتك. يحصل المفتاح الافتراضي على id
القيمة افتراضيًا عند عدم تمريره، لذا يمكنك اختصار المثال من الأعلى إلى:
const index = new Document ( {
document : {
index : [ "content" ]
}
} ) ;
يحتوي index
الأعضاء على قائمة بالحقول التي تريد فهرستها من مستنداتك. عند تحديد حقل واحد فقط، يمكنك تمرير سلسلة. عند استخدام id
المفتاح الافتراضي أيضًا، يتم اختصار هذا إلى:
const index = new Document ( { document : "content" } ) ;
index . add ( { id : 0 , content : "some text" } ) ;
بافتراض أن لديك عدة حقول، يمكنك إضافة حقول متعددة إلى الفهرس:
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" ]
} ) ;
يمكنك تمرير خيارات مخصصة لكل حقل:
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
}
} ]
} ) ;
يتم توريث خيارات الحقل عند تمرير الخيارات العامة أيضًا، على سبيل المثال:
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
}
} ]
}
} ) ;
ملاحظة: يتم أيضًا توريث خيارات السياق من حقل "المحتوى" من خلال خيارات الحقل المقابلة، في حين تم توريث خيارات الحقل هذه من خلال الخيار العام.
افترض أن مصفوفة المستندات تبدو أكثر تعقيدًا (تحتوي على فروع متداخلة وما إلى ذلك)، على سبيل المثال:
{
"record" : {
"id" : 0 ,
"title" : " some title " ,
"content" : {
"header" : " some text " ,
"footer" : " some text "
}
}
}
ثم استخدم علامة النقطتين المفصولتين root:child:child
لتحديد التسلسل الهرمي داخل واصف المستند:
const index = new Document ( {
document : {
id : "record:id" ,
index : [
"record:title" ,
"record:content:header" ,
"record:content:footer"
]
}
} ) ;
ما عليك سوى إضافة الحقول التي تريد الاستعلام عنها. لا تقم بإضافة حقول إلى الفهرس، فأنت تحتاج فقط إلى النتيجة (لكن لم تقم بالاستعلام عنها). ولهذا الغرض، يمكنك تخزين المستندات بشكل مستقل عن فهرسها (اقرأ أدناه).
عندما تريد الاستعلام عن حقل ما، يجب عليك تمرير المفتاح الدقيق للحقل الذي حددته في doc
كاسم حقل (مع بناء جملة النقطتين):
index . search ( query , {
index : [
"record:title" ,
"record:content:header" ,
"record:content:footer"
]
} ) ;
نفس:
index . search ( query , [
"record:title" ,
"record:content:header" ,
"record:content:footer"
] ) ;
استخدام الخيارات الخاصة بالحقل:
index . search ( [ {
field : "record:title" ,
query : "some query" ,
limit : 100 ,
suggest : true
} , {
field : "record:title" ,
query : "some other query" ,
limit : 100 ,
suggest : true
} ] ) ;
يمكنك إجراء بحث في نفس الحقل باستخدام استعلامات مختلفة.
عند تمرير الخيارات الخاصة بالحقل، يتعين عليك توفير التكوين الكامل لكل حقل. لا يتم توريثها مثل واصف المستند.
يجب عليك اتباع قاعدتين لمستنداتك:
[ // <-- not allowed as document start!
{
"id" : 0 ,
"title" : "title"
}
]
{
"records" : [ // <-- not allowed when ID or tag lives inside!
{
"id" : 0 ,
"title" : "title"
}
]
}
فيما يلي مثال لمستند معقد مدعوم:
{
"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 " ]
}
]
}
يبدو واصف المستند المقابل (عندما يجب فهرسة جميع الحقول) كما يلي:
const index = new Document ( {
document : {
id : "meta:id" ,
tag : "meta:tag" ,
index : [
"contents[]:body:title" ,
"contents[]:body:footer" ,
"contents[]:keywords"
]
}
} ) ;
مرة أخرى، عند البحث، يجب عليك استخدام نفس السلسلة المفصولة بنقطتين من تعريف الحقل الخاص بك.
index . search ( query , {
index : "contents[]:body:title"
} ) ;
هذا المثال يكسر القاعدتين المذكورتين أعلاه:
[ // <-- 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" ]
}
]
}
]
تحتاج إلى تطبيق نوع من تطبيع الهيكل.
يبدو الحل البديل لبنية البيانات هذه كما يلي:
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
} ] ) ;
يمكنك تخطي الحلقة الأولى عندما تحتوي بيانات المستند على فهرس واحد فقط كمصفوفة خارجية.
إضافة مستند إلى الفهرس:
index . add ( {
id : 0 ,
title : "Foo" ,
content : "Bar"
} ) ;
تحديث الفهرس بكائن واحد أو مجموعة من الكائنات:
index . update ( {
data : {
id : 0 ,
title : "Foo" ,
body : {
content : "Bar"
}
}
} ) ;
إزالة كائن واحد أو مجموعة من الكائنات من الفهرس:
index . remove ( docs ) ;
عندما يصبح المعرف معروفًا، يمكنك أيضًا إزالته ببساطة عن طريق (أسرع):
index . remove ( id ) ;
في المثال المعقد أعلاه، keywords
للحقل عبارة عن مصفوفة ولكن هنا لا يحتوي الترميز على أقواس مثل keywords[]
. سيؤدي ذلك أيضًا إلى اكتشاف المصفوفة، ولكن بدلاً من إلحاق كل إدخال بسياق جديد، سيتم ضم المصفوفة في سلسلة كبيرة وإضافتها إلى الفهرس.
الفرق بين كلا النوعين من إضافة محتويات المصفوفة هو مدى ملاءمتها عند البحث. عند إضافة كل عنصر من عناصر المصفوفة عبر append()
إلى سياقها الخاص باستخدام field[]
، فإن أهمية الإدخال الأخير المتزامن مع الإدخال الأول. عندما تترك الأقواس في الترميز، ستنضم المصفوفة إلى سلسلة واحدة مفصولة بمسافات بيضاء. هنا الإدخال الأول له أعلى صلة، في حين أن الإدخال الأخير له أدنى صلة.
لذا بافتراض أن الكلمة الرئيسية من المثال أعلاه تم فرزها مسبقًا حسب مدى صلتها بشعبيتها، فأنت تريد الاحتفاظ بهذا الترتيب (المعلومات ذات الصلة). لهذا الغرض، لا تقم بإضافة قوسين إلى التدوين. وإلا، فسيأخذ الإدخالات في سياق تسجيل جديد (سيتم فقدان الترتيب القديم).
يمكنك أيضًا ترك تدوين القوس للحصول على أداء أفضل ومساحة ذاكرة أصغر. استخدمه عندما لا تحتاج إلى دقة الملاءمة للإدخالات.
البحث في كافة المجالات:
index . search ( query ) ;
البحث في مجال محدد:
index . search ( query , { index : "title" } ) ;
البحث من خلال مجموعة معينة من الحقول:
index . search ( query , { index : [ "title" , "content" ] } ) ;
نفس:
index . search ( query , [ "title" , "content" ] ) ;
قم بتمرير المعدلات والاستعلامات المخصصة لكل حقل:
index . search ( [ {
field : "content" ,
query : "some query" ,
limit : 100 ,
suggest : true
} , {
field : "content" ,
query : "some other query" ,
limit : 100 ,
suggest : true
} ] ) ;
يمكنك إجراء بحث في نفس الحقل باستخدام استعلامات مختلفة.
شاهد جميع خيارات البحث الميداني المتاحة.
مخطط مجموعة النتائج:
fields[] => { field, result[] => { document }}
الفهرس الأول عبارة عن مجموعة من الحقول التي تم تطبيق الاستعلام عليها. يحتوي كل حقل من هذا الحقل على سجل (كائن) له خاصيتان "الحقل" و"النتيجة". "النتيجة" هي أيضًا مصفوفة وتتضمن نتيجة هذا الحقل المحدد. يمكن أن تكون النتيجة مجموعة من المعرفات أو غنية ببيانات المستند المخزنة.
تبدو مجموعة النتائج غير المعززة الآن كما يلي:
[ {
field : "title" ,
result : [ 0 , 1 , 2 ]
} , {
field : "content" ,
result : [ 3 , 4 , 5 ]
} ]
تبدو مجموعة النتائج المحسّنة الآن كما يلي:
[ {
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 */ } }
]
} ]
عند استخدام pluck
بدلاً من "field"، يمكنك تحديد حقل واحد فقط بشكل صريح والحصول على تمثيل ثابت:
index . search ( query , { pluck : "title" , enrich : true } ) ;
[
{ id : 0 , doc : { /* document */ } } ,
{ id : 1 , doc : { /* document */ } } ,
{ id : 2 , doc : { /* document */ } }
]
مجموعة النتائج هذه هي بديل لـ "البحث المنطقي". بدلاً من تطبيق المنطق المنطقي الخاص بك على كائن متداخل، يمكنك تطبيق المنطق الخاص بك بنفسك أعلى مجموعة النتائج ديناميكيًا. وهذا يفتح إمكانيات هائلة حول كيفية معالجة النتائج. ولذلك، لن يتم ضغط النتائج من الحقول في نتيجة واحدة بعد الآن. يؤدي ذلك إلى الاحتفاظ ببعض المعلومات المهمة، مثل اسم الحقل بالإضافة إلى مدى ملاءمة كل نتائج الحقل والتي لم تعد مختلطة.
سيؤدي البحث الميداني إلى تطبيق استعلام باستخدام المنطق المنطقي "أو" بشكل افتراضي. كل حقل له نتيجة خاصة به للاستعلام المحدد.
هناك موقف واحد حيث لا تزال الخاصية bool
مدعومة. عندما ترغب في تبديل منطق "أو" الافتراضي من البحث الميداني إلى "و"، على سبيل المثال:
index . search ( query , {
index : [ "title" , "content" ] ,
bool : "and"
} ) ;
سوف تحصل فقط على النتائج التي تحتوي على الاستعلام في كلا الحقلين. هذا كل شيء.
مثل key
المعرف، ما عليك سوى تحديد المسار إلى العلامة:
const index = new Document ( {
document : {
id : "id" ,
tag : "tag" ,
index : "content"
}
} ) ;
index . add ( {
id : 0 ,
tag : "cat" ,
content : "Some content ..."
} ) ;
يمكن أن تحتوي بياناتك أيضًا على علامات متعددة كمصفوفة:
index . add ( {
id : 1 ,
tag : [ "animal" , "dog" ] ,
content : "Some content ..."
} ) ;
يمكنك إجراء بحث خاص بالعلامة عن طريق:
index . search ( query , {
index : "content" ,
tag : "animal"
} ) ;
يمنحك هذا فقط النتيجة التي تم وضع علامة عليها بالعلامة المحددة.
استخدم علامات متعددة عند البحث:
index . search ( query , {
index : "content" ,
tag : [ "cat" , "dog" ]
} ) ;
يمنحك هذا نتيجة تم وضع علامة عليها بإحدى العلامات المحددة.
سيتم تطبيق علامات متعددة باعتبارها "أو" منطقية بشكل افتراضي. إنها تحتاج فقط إلى وجود إحدى العلامات.
هذا موقف آخر حيث لا تزال خاصية bool
مدعومة. عندما ترغب في تبديل المنطق الافتراضي "أو" من العلامة، ابحث في "و"، على سبيل المثال:
index . search ( query , {
index : "content" ,
tag : [ "dog" , "animal" ] ,
bool : "and"
} ) ;
ستحصل فقط على نتائج تحتوي على كلتا العلامتين (في هذا المثال يوجد سجل واحد فقط يحتوي على العلامة "كلب" و"حيوان").
يمكنك أيضًا جلب النتائج من علامة واحدة أو أكثر في حالة عدم تمرير أي استعلام:
index . search ( { tag : [ "cat" , "dog" ] } ) ;
في هذه الحالة تبدو مجموعة النتائج كما يلي:
[ {
tag : "cat" ,
result : [ /* all cats */ ]
} , {
tag : "dog" ,
result : [ /* all dogs */ ]
} ]
افتراضيًا، يقتصر كل استعلام على 100 إدخال. الاستعلامات غير المحدودة تؤدي إلى مشاكل. تحتاج إلى تعيين الحد كخيار لضبط الحجم.
يمكنك تعيين الحد والإزاحة لكل استعلام:
index . search ( query , { limit : 20 , offset : 100 } ) ;
لا يمكنك حساب حجم مجموعة النتائج مسبقًا. هذا هو الحد الذي يحدده تصميم FlexSearch. عندما تحتاج حقًا إلى حساب جميع النتائج التي يمكنك تصفحها، فما عليك سوى تعيين حد مرتفع بدرجة كافية واستعادة جميع النتائج وتطبيق إزاحة الترحيل يدويًا (يعمل هذا أيضًا على جانب الخادم). يعد FlexSearch سريعًا بدرجة كافية بحيث لا يمثل هذا مشكلة.
يمكن أن يحتوي فهرس المستندات فقط على مخزن. يمكنك استخدام فهرس المستند بدلاً من الفهرس المسطح للحصول على هذه الوظيفة أيضًا عند تخزين أزواج محتوى المعرفات فقط.
يمكنك تحديد الحقول التي يجب فهرستها بشكل مستقل وأي الحقول يجب تخزينها. بهذه الطريقة يمكنك فهرسة الحقول التي لا ينبغي تضمينها في نتيجة البحث.
لا تستخدم متجرًا عندما: 1. مجموعة من المعرفات لأن النتيجة جيدة بما فيه الكفاية، أو 2. لديك بالفعل محتويات/مستندات مخزنة في مكان آخر (خارج الفهرس).
عندما يتم تعيين سمة
store
، يجب عليك تضمين جميع الحقول التي يجب تخزينها بشكل صريح (تعمل مثل القائمة البيضاء).
عندما لم يتم تعيين سمة
store
، يتم تخزين المستند الأصلي كبديل.
سيؤدي هذا إلى إضافة المحتوى الأصلي بالكامل إلى المتجر:
const index = new Document ( {
document : {
index : "content" ,
store : true
}
} ) ;
index . add ( { id : 0 , content : "some text" } ) ;
يمكنك الحصول على المستندات المفهرسة من المتجر:
var data = index . get ( 1 ) ;
يمكنك تحديث/تغيير محتويات المتجر مباشرة دون تغيير الفهرس عن طريق:
index . set ( 1 , data ) ;
لتحديث المتجر وتحديث الفهرس أيضًا، استخدم فقط index.update
أو index.add
أو index.append
.
عندما تقوم بإجراء استعلام، سواء كان فهرس مستند أو فهرسًا مسطحًا، فسوف تحصل دائمًا على مجموعة من المعرفات.
اختياريًا، يمكنك إثراء نتائج الاستعلام تلقائيًا بالمحتويات المخزنة عن طريق:
index . search ( query , { enrich : true } ) ;
تبدو نتائجك الآن كما يلي:
[ {
id : 0 ,
doc : { /* content from store */ }
} , {
id : 1 ,
doc : { /* content from store */ }
} ]
سيؤدي هذا إلى إضافة حقول محددة فقط من مستند إلى المتجر (المعرف ليس ضروريًا للاحتفاظ به في المتجر):
const index = new Document ( {
document : {
index : "content" ,
store : [ "author" , "email" ]
}
} ) ;
index . add ( id , content ) ;
يمكنك تكوين ما يجب فهرسته وما يجب تخزينه بشكل مستقل. يوصى بشدة باستخدام هذا كلما استطعت.
فيما يلي مثال مفيد لتكوين المستند والمتجر:
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 ..."
} ) ;
يمكنك الاستعلام عن المحتويات وستستعيد القيم المخزنة بدلاً من ذلك:
index . search ( "some content" , { enrich : true } ) ;
تبدو نتائجك الآن كما يلي:
[ {
field : "content" ,
result : [ {
id : 0 ,
doc : {
author : "Jon Doe" ,
email : "[email protected]" ,
}
} ]
} ]
لم يتم فهرسة كلا الحقلين "المؤلف" و"البريد الإلكتروني".
ببساطة طرق السلسلة مثل:
var index = FlexSearch . create ( )
. addMatcher ( { 'â' : 'a' } )
. add ( 0 , 'foo' )
. add ( 1 , 'bar' ) ;
index . remove ( 0 ) . update ( 1 , 'foo' ) . add ( 2 , 'foobar' ) ;
ملاحظة: يتم تعطيل هذه الميزة بشكل افتراضي بسبب استخدامها الموسع للذاكرة. اقرأ هنا للحصول على مزيد من المعلومات حول وكيفية التمكين.
يقدم FlexSearch آلية تسجيل جديدة تسمى البحث السياقي والتي اخترعها توماس ويكرلينج، مؤلف هذه المكتبة. يعمل البحث السياقي على تعزيز الاستعلامات بشكل لا يصدق إلى مستوى جديد تمامًا ولكنه يتطلب أيضًا بعض الذاكرة الإضافية (اعتمادًا على العمق ). الفكرة الأساسية لهذا المفهوم هي تحديد الملاءمة من خلال سياقها بدلاً من حساب الملاءمة من خلال المسافة الكاملة للوثيقة المقابلة لها. وبهذه الطريقة، يعمل البحث السياقي أيضًا على تحسين نتائج الاستعلامات القائمة على الصلة بكمية كبيرة من البيانات النصية.
قم بإنشاء فهرس واستخدم السياق الافتراضي:
var index = new FlexSearch ( {
tokenize : "strict" ,
context : true
} ) ;
قم بإنشاء فهرس وتطبيق الخيارات المخصصة للسياق:
var index = new FlexSearch ( {
tokenize : "strict" ,
context : {
resolution : 5 ,
depth : 3 ,
bidirectional : true
}
} ) ;
يتم دعم الرمز المميز "الصارم" فقط بواسطة الفهرس السياقي.
يتطلب الفهرس السياقي مقدارًا إضافيًا من الذاكرة اعتمادًا على العمق.
تحتاج إلى تهيئة ذاكرة التخزين المؤقت وحدودها أثناء إنشاء الفهرس:
const index = new Index ( { cache : 100 } ) ;
const results = index . searchCache ( query ) ;
السيناريو الشائع لاستخدام ذاكرة التخزين المؤقت هو الإكمال التلقائي أو البحث الفوري عند الكتابة.
عند تمرير رقم كحد، تقوم ذاكرة التخزين المؤقت تلقائيًا بموازنة الإدخالات المخزنة المتعلقة بشعبيتها.
عند استخدام "صحيح" فقط، تكون ذاكرة التخزين المؤقت غير محدودة ويتم تنفيذها بشكل أسرع بمقدار 2-3 مرات (لأن الموازن ليس من الضروري تشغيله).
ينقسم نموذج العامل الجديد من الإصدار 0.7.0 إلى "حقول" من المستند (عامل واحد = فهرس حقل واحد). وبهذه الطريقة يصبح العامل قادراً على حل المهام (المهام الفرعية) بشكل كامل. الجانب السلبي لهذا النموذج هو أنه ربما لم يكن متوازنًا تمامًا في تخزين المحتويات (قد تحتوي الحقول على أطوال مختلفة من المحتويات). من ناحية أخرى، لا يوجد ما يشير إلى أن موازنة التخزين تعطي أي ميزة (جميعها تتطلب نفس المقدار في المجموع).
عند استخدام فهرس المستندات، فما عليك سوى تطبيق خيار "العامل":
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" }
عندما تقوم بإجراء بحث ميداني في جميع الحقول، فإن هذه المهمة تتم موازنةها بشكل مثالي من خلال جميع العاملين، مما يمكنهم من حل مهامهم الفرعية بشكل مستقل.
لقد رأينا أعلاه أن المستندات ستقوم بإنشاء عامل تلقائيًا لكل حقل. يمكنك أيضًا إنشاء WorkerIndex مباشرة (مثل استخدام Index
بدلاً من Document
).
استخدم كوحدة 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" ) ;
أو عند استخدام الإصدار المجمع بدلاً من ذلك:
var index = new FlexSearch . Worker ( options ) ;
index . add ( 1 , "some" )
. add ( 2 , "content" )
. add ( 3 , "to" )
. add ( 4 , "index" ) ;
يعمل WorkerIndex هذا تمامًا مثل مثيل Index
الذي تم إنشاؤه.
يدعم WorkerIndex فقط المتغير
async
لجميع الطرق. هذا يعني أنه عند استدعاءindex.search()
على WorkerIndex، سيؤدي هذا أيضًا بشكل غير متزامن بنفس الطريقة التي سيعمل بهاindex.searchAsync()
.
يعتمد نموذج العامل لـ Node.js على "سلاسل العمل" ويعمل بنفس الطريقة تمامًا:
const { Document } = require ( "flexsearch" ) ;
const index = new Document ( {
index : [ "tag" , "name" , "title" , "text" ] ,
worker : true
} ) ;
أو أنشئ نسخة عاملة واحدة لفهرس غير مستند:
const { Worker } = require ( "flexsearch" ) ;
const index = new Worker ( { options } ) ;
سيعمل العامل دائمًا كغير متزامن. في استدعاء أسلوب الاستعلام، يجب عليك دائمًا التعامل مع الوعد الذي تم إرجاعه (على سبيل المثال، استخدام await
) أو تمرير وظيفة رد الاتصال كمعلمة أخيرة.
const index = new Document ( {
index : [ "tag" , "name" , "title" , "text" ] ,
worker : true
} ) ;
سيتم تشغيل جميع الطلبات والمهام الفرعية بالتوازي (إعطاء الأولوية "لإتمام جميع المهام"):
index . searchAsync ( query , callback ) ;
index . searchAsync ( query , callback ) ;
index . searchAsync ( query , callback ) ;
أيضًا (حدد الأولوية "تم إكمال جميع المهام"):
index . searchAsync ( query ) . then ( callback ) ;
index . searchAsync ( query ) . then ( callback ) ;
index . searchAsync ( query ) . then ( callback ) ;
أو عندما يكون لديك رد اتصال واحد فقط عند الانتهاء من جميع الطلبات، ما عليك سوى استخدام Promise.all()
الذي يعطي أيضًا الأولوية "لإتمام جميع المهام":
Promise . all ( [
index . searchAsync ( query ) ,
index . searchAsync ( query ) ,
index . searchAsync ( query )
] ) . then ( callback ) ;
داخل رد الاتصال الخاص بـ Promise.all()
ستحصل أيضًا على مجموعة من النتائج كمعلمة أولى على التوالي لكل استعلام تقوم بإدخاله.
عند استخدام await
يمكنك تحديد أولويات الطلب (إعطاء الأولوية "اكتملت المهمة الأولى") وحل الطلبات واحدًا تلو الآخر ومعالجة المهام الفرعية بالتوازي:
await index . searchAsync ( query ) ;
await index . searchAsync ( query ) ;
await index . searchAsync ( query ) ;
نفس الشيء بالنسبة إلى index.add()
أو index.append()
أو index.remove()
أو index.update()
. توجد هنا حالة خاصة لم يتم تعطيلها بواسطة المكتبة، ولكن عليك أن تضعها في الاعتبار عند استخدام العمال.
عند استدعاء الإصدار "المتزامن" في فهرس عامل:
index . add ( doc ) ;
index . add ( doc ) ;
index . add ( doc ) ;
// contents aren't indexed yet,
// they just queued on the message channel
بالطبع، يمكنك القيام بذلك ولكن ضع في اعتبارك أن مؤشر الترابط الرئيسي لا يحتوي على قائمة انتظار إضافية لمهام العامل الموزعة. يؤدي تشغيل هذه العناصر في حلقة طويلة إلى إطلاق المحتوى بشكل كبير إلى قناة الرسائل عبر worker.postMessage()
داخليًا. لحسن الحظ، سيتعامل المتصفح وNode.js مع هذه المهام الواردة تلقائيًا (طالما توفر ذاكرة الوصول العشوائي المجانية الكافية). عند استخدام الإصدار "المتزامن" في فهرس عامل، لا تتم فهرسة المحتوى بسطر واحد أدناه، لأنه يتم التعامل مع جميع الاستدعاءات على أنها غير متزامنة افتراضيًا.
عند إضافة/تحديث/إزالة كميات كبيرة من المحتوى إلى الفهرس (أو التردد العالي)، يوصى باستخدام الإصدار غير المتزامن مع
async/await
للحفاظ على مساحة منخفضة للذاكرة أثناء العمليات الطويلة.
لقد تغيرت عملية التصدير قليلاً. وتتكون عملية التصدير الآن من عدة أجزاء أصغر، بدلاً من قطعة واحدة كبيرة فقط. تحتاج إلى تمرير وظيفة رد الاتصال التي تحتوي على وسيطتين "مفتاح" و"بيانات". يتم استدعاء وظيفة رد الاتصال هذه بواسطة كل جزء، على سبيل المثال:
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 ) ;
} ) ;
لا يعد تصدير البيانات إلى localStorage ممارسة جيدة حقًا، ولكن إذا لم يكن الحجم مصدر قلق، فاستخدمه إذا أردت. التصدير موجود بشكل أساسي للاستخدام في Node.js أو لتخزين الفهارس التي تريد تفويضها من الخادم إلى العميل.
يتوافق حجم التصدير مع استهلاك ذاكرة المكتبة. لتقليل حجم التصدير، يتعين عليك استخدام تكوين له مساحة ذاكرة أقل (استخدم الجدول الموجود في الأسفل للحصول على معلومات حول التكوينات وتخصيص الذاكرة الخاصة بها).
عندما يتم تشغيل روتين الحفظ الخاص بك بشكل غير متزامن، يجب عليك إرجاع الوعد:
index . export ( function ( key , data ) {
return new Promise ( function ( resolve ) {
// do the saving as async
resolve ( ) ;
} ) ;
} ) ;
لا يمكنك تصدير الجدول الإضافي لميزة "التحديث السريع". يوجد هذا الجدول من المراجع، وعند تخزينه يتم إجراء تسلسل كامل له ويصبح كبيرًا جدًا. سوف يتعامل lib مع هذه الأمور تلقائيًا نيابةً عنك. عند استيراد البيانات، يقوم الفهرس تلقائيًا بتعطيل "التحديث السريع".
قبل أن تتمكن من استيراد البيانات، تحتاج إلى إنشاء الفهرس الخاص بك أولاً. بالنسبة لفهارس المستندات، قم بتوفير نفس واصف المستند الذي استخدمته عند تصدير البيانات. لا يتم تخزين هذا التكوين في التصدير.
var index = new Index ( { ... } ) ;
لاستيراد البيانات، ما عليك سوى تمرير المفتاح والبيانات:
index . import ( key , localStorage . getItem ( key ) ) ;
تحتاج إلى استيراد كل مفتاح! وإلا فإن الفهرس الخاص بك لا يعمل. تحتاج إلى تخزين المفاتيح من التصدير واستخدام هذه المفاتيح للاستيراد (يمكن أن يختلف ترتيب المفاتيح).
هذا للتوضيح فقط ولا يوصى به، لأنه قد يكون لديك مفاتيح أخرى في وحدة التخزين المحلية الخاصة بك والتي لا يتم دعمها كاستيراد:
var keys = Object . keys ( localStorage ) ;
for ( let i = 0 , key ; i < keys . length ; i ++ ) {
key = keys [ i ] ;
index . import ( key , localStorage . getItem ( key ) ) ;
}
تنقسم التعريفات الخاصة باللغة إلى مجموعتين:
function(string):string[]
boolean
{string: string}
{string: string}
string[]
تحتوي مجموعة الأحرف على منطق الترميز، وتحتوي اللغة على Stemer ومرشح StopWord والمطابقات. يمكن لتعريفات اللغات المتعددة استخدام نفس برنامج تشفير مجموعة الأحرف. ويتيح لك هذا الفصل أيضًا إدارة تعريفات اللغة المختلفة لحالات الاستخدام الخاصة (مثل الأسماء والمدن واللهجات/اللغة العامية وما إلى ذلك).
لوصف لغة مخصصة بشكل كامل بسرعة، عليك اجتياز ما يلي:
const index = FlexSearch ( {
// mandatory:
encode : ( content ) => [ words ] ,
// optionally:
rtl : false ,
stemmer : { } ,
matcher : { } ,
filter : [ ]
} ) ;
عند عدم تمرير أي معلمة، فإنه يستخدم المخطط latin:default
افتراضيًا.
مجال | فئة | وصف |
ترميز | مجموعة محارف | وظيفة التشفير. يجب إرجاع مجموعة من الكلمات المنفصلة (أو سلسلة فارغة). |
rtl | مجموعة محارف | خاصية منطقية تشير إلى التشفير من اليمين إلى اليسار. |
فلتر | لغة | يُعرف عامل التصفية أيضًا باسم "كلمات التوقف"، حيث يقوم بتصفية الكلمات تمامًا من فهرستها. |
ستيمر | لغة | يقوم Stemmer بإزالة نهايات الكلمات وهو نوع من "التطبيع الجزئي". نهاية الكلمة متطابقة فقط عندما يكون طول الكلمة أكبر من الجزء المطابق. |
المطابق | لغة | يستبدل المطابق جميع تكرارات سلسلة معينة بغض النظر عن موضعها، وهو أيضًا نوع من "التطبيع الجزئي". |
إن أبسط طريقة لتعيين ترميز محدد لمجموعة الأحرف/اللغة عبر الوحدات النمطية هي:
import charset from "./dist/module/lang/latin/advanced.js" ;
import lang from "./dist/module/lang/en.js" ;
const index = FlexSearch ( {
charset : charset ,
lang : lang
} ) ;
ما عليك سوى استيراد التصدير الافتراضي لكل وحدة وتعيينها وفقًا لذلك.
المثال المؤهل الكامل من الأعلى هو:
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
} ) ;
المثال أعلاه هو الواجهة القياسية التي يتم تصديرها على الأقل من كل مجموعة أحرف/لغة.
يمكنك أيضًا تحديد برنامج التشفير مباشرةً وترك جميع الخيارات الأخرى:
import simple from "./dist/module/lang/latin/simple.js" ;
const index = FlexSearch ( {
encode : simple
} ) ;
يمكنك تعيين مجموعة أحرف عن طريق تمرير مجموعة الأحرف أثناء التهيئة، على سبيل المثال charset: "latin"
لمشفر مجموعة الأحرف الافتراضية أو charset: "latin:soundex"
لمتغير التشفير.
يمكن أيضًا استخدام تعريفات اللغة (خاصة المطابقات) لتطبيع اللهجة العامية للغة معينة.
تحتاج إلى إتاحة مجموعة الأحرف و/أو تعريفات اللغة عن طريق:
flexsearch.bundle.js
افتراضيًا، ولكن لا يتم تضمين تعريفات خاصة باللغة/dist/lang/
(تشير الملفات إلى اللغات، والمجلدات عبارة عن مجموعات محارف)عند تحميل حزم اللغات ، تأكد من تحميل المكتبة من قبل:
< script src =" dist/flexsearch.light.js " > </ script >
< script src =" dist/lang/latin/default.min.js " > </ script >
< script src =" dist/lang/en.min.js " > </ script >
عند استخدام إصدار "الحزمة" الكامل ، يتم تضمين عمليات التشفير اللاتينية المدمجة بالفعل وعليك فقط تحميل ملف اللغة:
< script src =" dist/flexsearch.bundle.js " > </ script >
< script src =" dist/lang/en.min.js " > </ script >
نظرًا لأنك تقوم بتحميل العبوات كحزم خارجية (لا توجد علامات غير ES6) عليك تهيئتها عن طريق الاختصارات:
const index = FlexSearch ( {
charset : "latin:soundex" ,
lang : "en"
} ) ;
استخدم
charset:variant
لتعيين charset ومتغيراته. عند تمرير charset فقط بدون متغير ، سيتم حل تلقائيًا كـcharset:default
.
يمكنك أيضًا تجاوز التعريفات الحالية ، على سبيل المثال:
const index = FlexSearch ( {
charset : "latin" ,
lang : "en" ,
matcher : { }
} ) ;
لن يتم تمديد التعاريف التي تم تمريرها التعريفات الافتراضية ، وسوف تحل محلها.
عندما ترغب في توسيع تعريف ما ، فقط قم بإنشاء ملف لغة جديد ووضعه في كل المنطق.
إنه مستقيم إلى الأمام بشكل مستقيم عند استخدام متغير التشفير:
< 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 >
عند استخدام إصدار "الحزمة" الكامل ، يتم تضمين عمليات التشفير اللاتينية المدمجة بالفعل وعليك فقط تحميل ملف اللغة:
< 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"
} ) ;
في FlexSearch ، لا يمكنك توفير الرمز المميز الجزئي الخاص بك ، لأنه تبعية مباشرة على الوحدة الأساسية. يقوم الرمز المميز المدمج لـ FlexSearch بتقسيم كل كلمة إلى شظايا بأنماط مختلفة:
هذا هو خط الأنابيب الافتراضي الذي توفره FlexSearch:
في البداية ، ألق نظرة على خط الأنابيب الافتراضي في src/common.js
. إنه بسيط للغاية ومباشر للأمام. ستعامل خط الأنابيب كنوع من الانقلاب للتحكم ، ويجب أن يتعامل تطبيق التشفير النهائي مع التحولات المحددة للغة. لقد ترك هذا الحل من العديد من الاختبارات.
حقن خط الأنابيب الافتراضي على سبيل المثال:
this . pipeline (
/* string: */ str . toLowerCase ( ) ,
/* normalize: */ false ,
/* split: */ split ,
/* collapse: */ false
) ;
استخدم مخطط خط الأنابيب من الأعلى لفهم التكرار وفرق ما قبل الترميز وما بعد الترميز. يجب تطبيق STEMMER والمطابقات بعد تطبيع Charset ولكن قبل التحولات اللغوية ، مرشحات أيضًا.
فيما يلي مثال جيد على توسيع خطوط الأنابيب: src/lang/latin/extra.js
→ src/lang/latin/advanced.js
→ src/lang/latin/simple.js
.
ابحث عن لغتك في src/lang/
، إذا كانت موجودة ، يمكنك تمديد أو توفير المتغيرات (مثل اللهجة/العامية). إذا لم تكن اللغة موجودة ، قم بإنشاء ملف جديد وتحقق مما إذا كان أي من charsets الحالي (مثل اللاتينية) يناسب لغتك. عندما لا توجد charset ، تحتاج إلى توفير charset كقاعدة للغة.
يجب أن يوفر Charset جديد على الأقل:
encode
وظيفة تقوم بتطبيع charset لمحتوى النص الذي تم تمريره (قم بإزالة chars الخاصة ، والتحولات اللغوية ، وما إلى ذلك) وإرجاع مجموعة من الكلمات المنفصلة . كما يجب تطبيق مرشح STEMMER أو Matcher أو STOPWORD هنا. عندما لا تحتوي اللغة على كلمات تأكد من تقديم شيء مشابه ، على سبيل المثال ، يمكن أن تكون كل علامة صينية أيضًا "كلمة". لا تُرجع محتوى النص بأكمله دون انقسام.rtl
علامة منطقية تشير إلى الترميز من اليمين إلى اليسارفي الأساس ، يحتاج Charset إلى توفير وظيفة تشفير إلى جانب مؤشر للترميز من اليمين إلى اليسار:
export function encode ( str ) { return [ str ] }
export const rtl = false ;
سلسلة مرجعية: "Björn-Phillipp Mayer"
استفسار | تقصير | بسيط | متقدم | إضافي |
بيورن | نعم | نعم | نعم | نعم |
بيور | نعم | نعم | نعم | نعم |
بيورن | لا | نعم | نعم | نعم |
bjoern | لا | لا | نعم | نعم |
فيليب | لا | لا | نعم | نعم |
فيليب | لا | لا | نعم | نعم |
björnphillip | لا | نعم | نعم | نعم |
ماير | لا | لا | نعم | نعم |
بيورن ماير | لا | لا | نعم | نعم |
ماير fhilip | لا | لا | نعم | نعم |
بيرن ماير | لا | لا | لا | نعم |
(إيجابيات كاذبة) | لا | لا | لا | نعم |
تم فهرسة كتاب "Gulliver's Travels Swift Jonathan 1726" بالكامل للأمثلة أدناه.
سوف يخصص الإعداد الأكثر أهمية للذاكرة 1.2 ميغابايت فقط للكتاب بأكمله المفهرس! ربما تكون هذه هي أكثر البصمة للذاكرة الصغيرة التي ستحصل عليها من مكتبة البحث.
import { encode } from "./lang/latin/extra.js" ;
index = new Index ( {
encode : encode ,
tokenize : "strict" ,
optimize : true ,
resolution : 1 ,
minlength : 3 ,
fastupdate : false ,
context : false
} ) ;
تم فهرسة كتاب "Gulliver's Travels" (Swift Jonathan 1726) تمامًا لهذا الاختبار:
افتراضيًا ، فهرس معجمي صغير جدًا:
depth: 0, bidirectional: 0, resolution: 3, minlength: 0
=> 2.1 ميغابايت
دقة أعلى ستزيد من تخصيص الذاكرة:
depth: 0, bidirectional: 0, resolution: 9, minlength: 0
=> 2.9 ميغابايت
سيؤدي استخدام فهرس السياق إلى زيادة تخصيص الذاكرة:
depth: 1, bidirectional: 0, resolution: 9, minlength: 0
=> 12.5 ميغابايت
سيؤدي عمق السياق الأعلى إلى زيادة تخصيص الذاكرة:
depth: 2, bidirectional: 0, resolution: 9, minlength: 0
=> 21.5 ميغابايت
سوف يقلل الطول العالي من تخصيص الذاكرة:
depth: 2, bidirectional: 0, resolution: 9, minlength: 3
=> 19.0 ميغابايت
سيؤدي استخدام ثنائية الاتجاه إلى تقليل تخصيص الذاكرة:
depth: 2, bidirectional: 1, resolution: 9, minlength: 3
=> 17.9 ميغابايت
إن تمكين خيار "fastupdate" سيزيد من تخصيص الذاكرة:
depth: 2, bidirectional: 1, resolution: 9, minlength: 3
=> 6.3 ميغابايت
كل مكتبة بحث في المنافسة باستمرار مع هذه الخصائص الأربعة:
يوفر لك FlexSearch العديد من المعلمات التي يمكنك استخدامها لضبط التوازن الأمثل لحالة الاستخدام المحددة الخاصة بك.
المعدل | تأثير الذاكرة * | تأثير الأداء ** | مطابقة التأثير ** | تأثير التسجيل ** |
دقة | +1 (لكل مستوى) | +1 (لكل مستوى) | 0 | +2 (لكل مستوى) |
عمق | +4 (لكل مستوى) | -1 (لكل مستوى) | -10 + العمق | +10 |
الطول | -2 (لكل مستوى) | +2 (لكل مستوى) | -3 (لكل مستوى) | +2 (لكل مستوى) |
ثنائية الاتجاه | -2 | 0 | +3 | -1 |
fastupdate | +1 | +10 (تحديث ، إزالة) | 0 | 0 |
تحسين: صحيح | -7 | -1 | 0 | -3 |
التشفير: "iCase" | 0 | 0 | 0 | 0 |
المشفر: "بسيط" | -2 | -1 | +2 | 0 |
التشفير: "متقدم" | -3 | -2 | +4 | 0 |
المشفر: "إضافي" | -5 | -5 | +6 | 0 |
المشفر: "Soundex" | -6 | -2 | +8 | 0 |
الرمز المميز: "صارم" | 0 | 0 | 0 | 0 |
الرمز المميز: "إلى الأمام" | +3 | -2 | +5 | 0 |
الرمز المميز: "عكسي" | +5 | -4 | +7 | 0 |
الرمز المميز: "كامل" | +8 | -5 | +10 | 0 |
فهرس المستندات | +3 (لكل حقل) | -1 (لكل حقل) | 0 | 0 |
علامات الوثيقة | +1 (لكل علامة) | -1 (لكل علامة) | 0 | 0 |
المتجر: صحيح | +5 (لكل مستند) | 0 | 0 | 0 |
المتجر: [الحقول] | +1 (لكل حقل) | 0 | 0 | 0 |
ذاكرة التخزين المؤقت: صحيح | +10 | +10 | 0 | 0 |
ذاكرة التخزين المؤقت: 100 | +1 | +9 | 0 | 0 |
نوع الهوية: الرقم | 0 | 0 | 0 | 0 |
نوع الهوية: سلسلة | +3 | -3 | 0 | 0 |
memory
(التحسين الأساسي للذاكرة)performance
(التحسين الأساسي للأداء)match
(الأمثل الأساسي للمطابقة)score
(التحسين الأساسي للتسجيل)default
(الملف الشخصي المتوازن الافتراضي)هذه الملامح تغطي حالات الاستخدام القياسية. يوصى بتطبيق التكوين المخصص بدلاً من استخدام الملفات الشخصية للحصول على أفضل ما في موقفك. يمكن تحسين كل ملف تعريف إلى مهمته المحددة ، على سبيل المثال التكوين الأمثل للأداء أو الذاكرة الشديدة وما إلى ذلك.
يمكنك تمرير إعداد مسبق أثناء إنشاء/تهيئة الفهرس.
يوصى باستخدام قيم المعرف الرقمي كمرجع عند إضافة محتوى إلى الفهرس. يؤثر طول البايت من IDS المنقولة على استهلاك الذاكرة بشكل كبير. إذا لم يكن ذلك ممكنًا ، فيجب أن تفكر في استخدام جدول الفهرس ورسم خريطة المعرفات مع الفهارس ، يصبح هذا مهمًا خاصة عند استخدام الفهارس السياقية على كمية كبيرة من المحتوى.
كلما استطعت ، حاول تقسيم المحتوى على الفئات وإضافتها إلى فهرسها الخاص ، على سبيل المثال:
var action = new FlexSearch ( ) ;
var adventure = new FlexSearch ( ) ;
var comedy = new FlexSearch ( ) ;
وبهذه الطريقة يمكنك أيضًا توفير إعدادات مختلفة لكل فئة. هذه في الواقع أسرع طريقة لإجراء بحث غامض.
لجعل هذا الحل القابل للتمديد أكثر ، يمكنك استخدام مساعد قصير:
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 ) : [ ] ;
}
أضف محتوى إلى الفهرس:
add ( 1 , "action" , "Movie Title" ) ;
add ( 2 , "adventure" , "Movie Title" ) ;
add ( 3 , "comedy" , "Movie Title" ) ;
أداء الاستفسارات:
var results = search ( "action" , "movie title" ) ; // --> [1]
تقسيم الفهارس حسب الفئات يحسن الأداء بشكل كبير.
حقوق الطبع والنشر 2018-2023 Thomas Wilkerling ، استضافتها NextApps GmbH
تم إصداره بموجب ترخيص Apache 2.0