让我们在这里讨论即将推出的 FlexSearch v0.8:#415
基本开始 • API 参考 • 文档索引 • 使用 Worker • 变更日志
您可以通过个人捐款来帮助我,以维持该项目的活力,并提供所有捐款来解决您的需求。
对立运营有限责任公司
就原始搜索速度而言,FlexSearch 的性能优于现有的所有搜索库,并且还提供灵活的搜索功能,例如多字段搜索、语音转换或部分匹配。
根据所使用的选项,它还提供最节省内存的索引。 FlexSearch 引入了一种名为“上下文索引”的新评分算法,该算法基于预先评分的词汇词典架构,与其他库相比,该架构的查询速度实际上快了 1,000,000 倍。 FlexSearch 还为您提供非阻塞异步处理模型以及 Web Worker,以通过专用平衡线程并行对索引执行任何更新或查询。
支持的平台:
图书馆比较《格列佛游记》:
插件(外部项目):
建造 | 文件 | 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 模块 | 下载 | 此 Github 存储库的/dist/module/文件夹 |
*捆绑包“flexsearch.es5.js”包含 EcmaScript 5 支持的 polyfill。
npm install flexsearch
Node.js 包包含
flexsearch.bundle.js
的所有功能。
特征 | flexsearch.bundle.js | flexsearch.compact.js | flexsearch.light.js |
预设 | ✓ | ✓ | - |
异步搜索 | ✓ | ✓ | - |
工人(Web + Node.js) | ✓ | - | - |
上下文索引 | ✓ | ✓ | ✓ |
索引文件(实地搜索) | ✓ | ✓ | - |
文件存储 | ✓ | ✓ | - |
部分匹配 | ✓ | ✓ | ✓ |
相关性评分 | ✓ | ✓ | ✓ |
按受欢迎程度自动平衡缓存 | ✓ | - | - |
标签 | ✓ | - | - |
建议 | ✓ | ✓ | - |
拼音匹配 | ✓ | ✓ | - |
可定制的字符集/语言(匹配器、编码器、分词器、词干分析器、过滤器、拆分、RTL) | ✓ | ✓ | ✓ |
出口/进口指数 | ✓ | - | - |
文件大小 (gzip) | 6.8 KB | 5.3 KB | 2.9 KB |
运行比较:性能基准“格列佛游记”
每秒操作数越高越好,除了测试“内存”,越低越好。
秩 | 图书馆 | 记忆 | 查询(单项) | 查询(多术语) | 查询(长) | 查询(重复) | 查询(未找到) |
1 | 弹性搜索 | 17 号 | 7084129 | 1586856 | 511585 | 2017142 | 3202006 |
2 | JSii | 27 | 6564 | 158149 | 61290 | 95098 | 534109 |
3 | 韦德 | 第424章 | 20471 | 78780 | 16693 | 225824 | 213754 |
4 | JS搜索 | 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
是一个存储 id-content-pairs 的扁平高性能索引。Worker
/ WorkerIndex
也是一个平面索引,它存储 id-content-pairs 但作为专用工作线程在后台运行。Document
是多字段索引,可以存储复杂的JSON文档(也可能存在worker索引)。根据您的情况,大多数人可能只需要其中之一。
< 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 >
AMD/CommonJS:
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-Support。
对
Worker
索引调用的每个方法都被视为异步。您将得到一个Promise
,或者您也可以提供一个回调函数作为最后一个参数。
全局方法:
索引方法:
WorkerIndex 方法:
文档方法:
*对于每个方法都存在一个异步等效方法:
异步版本:
异步方法将返回Promise
,或者您可以传递回调函数作为最后一个参数。
方法export
和import
始终是异步的,以及您在基于 Worker 的索引上调用的每个方法。
FlexSearch 是高度可定制的。使用正确的选项可以真正改善您的结果以及内存经济性和查询时间。
选项 | 价值观 | 描述 | 默认 |
预设 | “记忆” “表现” “匹配” “分数” “默认” | 配置文件作为快捷方式或作为自定义设置的基础。 | “默认” |
标记化 | “严格的” “向前” “撤销” “满的” | 索引模式(分词器)。 选择内置函数之一或传递自定义分词器函数。 | “严格的” |
缓存 | 布尔值 数字 | 启用/禁用和/或设置缓存条目的容量。 当传递一个数字作为限制时,缓存会自动平衡与其受欢迎程度相关的存储条目。 注意:当仅使用“true”时,缓存没有限制并且无限增长。 | 错误的 |
解决 | 数字 | 设置评分分辨率(默认值:9)。 | 9 |
语境 | 布尔值 上下文选项 | 启用/禁用上下文索引。当传递“true”作为值时,它将采用上下文的默认值。 | 错误的 |
优化 | 布尔值 | 启用后,它使用内存优化的堆栈流作为索引。 | 真的 |
促进 | 函数(arr,str,int)=>浮点数 | 将内容索引到索引时使用的自定义增强函数。该函数具有以下签名: Function(words[], term, index) => Float 。它有 3 个参数,您可以在其中获取所有单词的数组、当前术语以及该术语在单词数组中放置的当前索引。您可以应用自己的计算,例如术语的出现次数并返回该因子(<1 表示相关性降低,>1 表示相关性增加)。注意:此功能目前仅通过使用分词器“strict”来限制。 | 无效的 |
特定于语言的选项和编码: | |||
字符集 | 字符集有效负载 字符串(键) | 提供自定义字符集有效负载或传递内置字符集的键之一。 | “拉丁” |
语言 | 语言负载 字符串(键) | 提供自定义语言负载或传入内置语言的语言速记标志 (ISO-3166)。 | 无效的 |
编码 | 错误的 “默认” “简单的” “平衡” “先进的” “额外的” 函数(str)=> [单词] | 编码类型。 选择内置函数之一或传递自定义编码函数。 | “默认” |
词干分析器 | 错误的 细绳 功能 | 错误的 | |
筛选 | 错误的 细绳 功能 | 错误的 | |
匹配器 | 错误的 细绳 功能 | 错误的 | |
文档索引的其他选项: | |||
工人 | 布尔值 | 启用/禁用并设置正在运行的工作线程的计数。 | 错误的 |
文档 | 文档描述符 | 包括文档索引和存储的定义。 |
选项 | 价值观 | 描述 | 默认 |
解决 | 数字 | 设置上下文的评分分辨率(默认值:1)。 | 1 |
深度 | 错误的 数字 | 启用/禁用上下文索引并设置相关的上下文距离。深度是被认为相关的术语的最大单词/标记数。 | 1 |
双向 | 布尔值 | 设置双向搜索结果。如果启用并且源文本包含“red hat”,则查询“red hat”和“hat red”时将找到它。 | 真的 |
选项 | 价值观 | 描述 | 默认 |
ID | 细绳 | “ID”” | |
标签 | 错误的 细绳 | “标签” | |
指数 | 细绳 数组<字符串> 数组<对象> | ||
店铺 | 布尔值 细绳 数组<字符串> | 错误的 |
选项 | 价值观 | 描述 | 默认 |
分裂 | 错误的 正则表达式 细绳 | 使用非自定义分词器(内置,例如“forward”)时分割单词的规则。使用字符串/字符或使用正则表达式(默认: /W+/ )。 | /[W_]+/ |
回程 | 布尔值 | 启用从右到左编码。 | 错误的 |
编码 | 函数(str)=> [单词] | 自定义编码功能。 | /lang/latin/default.js |
选项 | 价值观 | 描述 |
词干分析器 | 错误的 细绳 功能 | 禁用或传递语言速记标志 (ISO-3166) 或自定义对象。 |
筛选 | 错误的 细绳 功能 | 禁用或传递语言速记标志 (ISO-3166) 或自定义数组。 |
匹配器 | 错误的 细绳 功能 | 禁用或传递语言速记标志 (ISO-3166) 或自定义数组。 |
选项 | 价值观 | 描述 | 默认 |
限制 | 数字 | 设置结果的限制。 | 100 |
抵消 | 数字 | 应用偏移(跳过项目)。 | 0 |
建议 | 布尔值 | 在结果中启用建议。 | 错误的 |
选项 | 价值观 | 描述 | 默认 |
指数 | 细绳 数组<字符串> 数组<对象> | 设置应搜索的文档字段。当没有设置字段时,将搜索所有字段。还支持每个字段的自定义选项。 | |
标签 | 细绳 数组<字符串> | 设置应搜索的文档字段。当没有设置字段时,将搜索所有字段。还支持每个字段的自定义选项。 | 错误的 |
丰富 | 布尔值 | 使用相应的文档丰富结果中的 ID。 | 错误的 |
布尔值 | “和” “或者” | 设置在多个字段或标签中搜索时使用的逻辑运算符。 | “或者” |
分词器还会影响所需的内存、查询时间和部分匹配的灵活性。尝试选择最符合您需求的分词器:
选项 | 描述 | 例子 | 记忆因子(n = 单词长度) |
“严格的” | 索引整个单词 | foobar | * 1 |
“向前” | 向前递增索引单词 | fo foob | * n |
“撤销” | 双向递增索引单词 | ar obar | * 2n - 1 |
“满的” | 索引所有可能的组合 | oba oob | * n * (n - 1) |
编码也会影响所需的内存,如查询时间和语音匹配。尝试选择这些编码器中最上面的一个满足您的需求,或者传入自定义编码器:
选项 | 描述 | 误报 | 压缩 |
错误的 | 关闭编码 | 不 | 0% |
“默认” | 不区分大小写的编码 | 不 | 0% |
“简单的” | 不区分大小写的编码 字符集标准化 | 不 | 〜3% |
“平衡” | 不区分大小写的编码 字符集标准化 字面转换 | 不 | 〜30% |
“先进的” | 不区分大小写的编码 字符集标准化 字面转换 语音规范化 | 不 | 〜40% |
“额外的” | 不区分大小写的编码 字符集标准化 字面转换 语音规范化 Soundex 变换 | 是的 | 〜 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
} ) ;
查看所有可用的自定义选项。
每个要添加到索引的内容都需要一个 ID。当您的内容没有 ID 时,您需要通过传递索引或计数或其他内容作为 ID 来创建一个 ID(强烈建议使用number
类型的值)。这些 ID 是对给定内容的唯一引用。当您通过现有 ID 更新或添加内容时,这一点很重要。当引用不是问题时,您可以简单地使用简单的东西,例如count++
。
指数。添加(id,字符串)
index . add ( 0 , "John Doe" ) ;
指数。搜索(字符串 | 选项,<限制>,<选项>)
index . search ( "John" ) ;
限制结果:
index . search ( "John" , 10 ) ;
您可以检查 ID 是否已被索引:
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)
时那样覆盖旧的索引内容。请记住,当 id 已经被索引时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")
时,您将获得索引 id 1 作为结果中的第一个条目,因为附加数据的上下文从零开始(不会堆叠到旧上下文),而这里的“index ” 是第一项。
如果您不希望出现此行为,则只需使用标准index.add(id, content)
并提供完整的内容长度。
指数。更新(id,字符串)
index . update ( 0 , "Max Miller" ) ;
指数。删除(id)
index . remove ( 0 ) ;
分词器将单词/术语拆分为组件或部分。
在创建/初始化期间定义私有自定义标记生成器:
var index = new FlexSearch ( {
tokenize : function ( str ) {
return str . split ( / s-/ / g ) ;
}
} ) ;
tokenizer 函数获取一个字符串作为参数,并且必须返回表示单词或术语的字符串数组。在某些语言中,每个字符都是一个术语,并且也不用空格分隔。
词干分析器:同一单词的几种语言突变(例如“run”和“running”)
过滤器:要从索引中过滤掉的单词黑名单(例如“and”、“to”或“be”)
在创建/初始化期间分配私有自定义词干分析器或过滤器:
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 ;
}
} ) ;
或者将词干分析器/过滤器全局分配给一种语言:
词干分析器作为对象(键值对)传递,过滤器作为数组传递。
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 时,至少将分词器设置为“reverse”或“full”。
只需将字段“rtl”设置为true并使用兼容的分词器:
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
成为 options 的主要成员。
对于新语法,字段“doc”被重命名为document
,字段“field”被重命名为index
:
const index = new Document ( {
document : {
id : "id" ,
index : [ "content" ]
}
} ) ;
index . add ( {
id : 0 ,
content : "some text"
} ) ;
字段id
描述了 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
} ] ) ;
您可以使用不同的查询在同一字段中执行搜索。
传递特定于字段的选项时,您需要提供每个字段的完整配置。它们不像文档描述符那样被继承。
您的文件需要遵循 2 条规则:
[ // <-- 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 ) ;
当 id 已知时,您也可以简单地通过(更快)删除:
index . remove ( id ) ;
在上面的复杂示例中,字段keywords
是一个数组,但这里的标记没有像keywords[]
这样的括号。这也将检测数组,但不是将每个条目附加到新的上下文,而是将数组连接到大字符串中并添加到索引中。
两种添加数组内容的区别在于搜索时的相关性。当使用语法field[]
通过append()
将数组的每个项目添加到其自己的上下文时,最后一个条目的相关性将与第一个条目并发。当您在符号中留下括号时,它将把数组连接到一个以空格分隔的字符串。这里第一个条目具有最高的相关性,而最后一个条目具有最低的相关性。
因此,假设上面示例中的关键字已根据其受欢迎程度的相关性进行了预先排序,那么您希望保持此顺序(相关性信息)。为此,请勿在符号中添加括号。否则,它将在新的评分上下文中获取条目(旧的顺序会丢失)。
您还可以保留括号符号以获得更好的性能和更小的内存占用。当您不需要条目的相关性粒度时可以使用它。
搜索所有字段:
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 }}
第一个索引是查询所应用到的字段数组。每个字段都有一个记录(对象),具有 2 个属性“字段”和“结果”。 “结果”也是一个数组,包含该特定字段的结果。结果可能是 ID 数组,也可能是通过存储的文档数据进行丰富的。
非丰富结果集现在看起来像:
[ {
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"
} ) ;
您将只获得在两个字段中都包含查询的结果。就是这样。
就像 ID 的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 足够快,这不是问题。
只有文档索引才能有存储。当仅存储 ID 内容对时,您也可以使用文档索引而不是平面索引来获得此功能。
您可以独立定义哪些字段应该被索引以及哪些字段应该被存储。这样您就可以索引不应包含在搜索结果中的字段。
在以下情况下不要使用存储: 1. ID 数组,因为结果足够好,或者 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
。
当您执行查询时,无论它是文档索引还是平面索引,您总是会返回一个 ID 数组。
您可以选择通过以下方式自动使用存储的内容丰富查询结果:
index . search ( query , { enrich : true } ) ;
您的结果现在看起来像:
[ {
id : 0 ,
doc : { /* content from store */ }
} , {
id : 1 ,
doc : { /* content from store */ }
} ]
这只会将文档中的特定字段添加到存储中(不需要将 ID 保留在存储中):
const index = new Document ( {
document : {
index : "content" ,
store : [ "author" , "email" ]
}
} ) ;
index . add ( id , content ) ;
您可以独立配置应索引的内容和应存储的内容。强烈建议您尽可能使用此功能。
这是配置 doc 和 store 的有用示例:
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 引入了一种称为上下文搜索的新评分机制,该机制是由该库的作者 Thomas Wilkerling 发明的。上下文搜索令人难以置信地将查询提升到一个全新的水平,但也需要一些额外的内存(取决于深度)。这个概念的基本思想是通过上下文来限制相关性,而不是通过其对应文档的整个距离来计算相关性。通过这种方式,上下文搜索还可以改进对大量文本数据进行基于相关性的查询的结果。
创建索引并使用默认上下文:
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 ) ;
使用缓存的常见场景是键入时自动完成或即时搜索。
当传递一个数字作为限制时,缓存会自动平衡与其受欢迎程度相关的存储条目。
当仅使用“true”时,缓存是无限制的,并且执行速度实际上快 2-3 倍(因为平衡器不必运行)。
v0.7.0 中的新工作模型被分为文档中的“字段”(1 个工作人员 = 1 个字段索引)。这样,工作人员就能够完全解决任务(子任务)。这种范例的缺点是它们在存储内容时可能没有完美平衡(字段可能具有不同的内容长度)。另一方面,没有迹象表明平衡存储会带来任何优势(它们总共需要相同的数量)。
当使用文档索引时,只需应用选项“worker”:
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
变体。这意味着当您在 WorkerIndex 上调用index.search()
时,这也将以与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()
也是如此。这里有一种特殊情况,库没有禁用它,但在使用 Workers 时需要记住。
当您在工作索引上调用“同步”版本时:
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 会自动为您处理此类传入任务(只要有足够的可用 RAM)。在工作索引上使用“同步”版本时,内容不会在下面一行索引,因为默认情况下所有调用都被视为异步。
当向索引添加/更新/删除大量内容(或高频)时,建议将异步版本与
async/await
一起使用,以在长时间进程中保持较低的内存占用。
出口略有变化。现在的出口由几个较小的部件组成,而不仅仅是一大堆。您需要传递一个回调函数,该函数有两个参数“key”和“data”。该回调函数由各个部分调用,例如:
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 ( ) ;
} ) ;
} ) ;
您无法导出“快速更新”功能的附加表。这些表存在引用,存储时它们完全序列化并变得太大。该库将自动为您处理这些问题。导入数据时,索引自动禁用“fastupdate”。
在导入数据之前,您需要先创建索引。对于文档索引,请提供导出数据时使用的相同文档描述符。此配置不存储在导出中。
var index = new Index ( { ... } ) ;
要导入数据,只需传递密钥和数据:
index . import ( key , localStorage . getItem ( key ) ) ;
您需要导入每个密钥!否则,您的索引将不起作用。您需要存储导出中的密钥并使用该密钥进行导入(密钥的顺序可能不同)。
这仅用于演示,不建议这样做,因为您的 localStorage 中可能有其他不支持导入的键:
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[]
字符集包含编码逻辑,语言包含词干分析器、停用词过滤器和匹配器。多种语言定义可以使用相同的字符集编码器。此外,这种分离还可以让您管理特殊用例的不同语言定义(例如名称、城市、方言/俚语等)。
要即时完整地描述自定义语言,您需要传递:
const index = FlexSearch ( {
// mandatory:
encode : ( content ) => [ words ] ,
// optionally:
rtl : false ,
stemmer : { } ,
matcher : { } ,
filter : [ ]
} ) ;
当不传递参数时,它默认使用latin:default
模式。
场地 | 类别 | 描述 |
编码 | 字符集 | 编码器功能。必须返回分隔单词的数组(或空字符串)。 |
回程 | 字符集 | 指示从右到左编码的布尔属性。 |
筛选 | 语言 | 过滤器也称为“停用词”,它们完全过滤掉被索引的单词。 |
词干分析器 | 语言 | 词干去除词尾,是一种“部分规范化”。当单词长度大于匹配的部分时,单词结尾就被匹配。 |
匹配器 | 语言 | Matcher 会替换给定字符串的所有出现位置,无论其位置如何,这也是一种“部分规范化”。 |
通过模块分配字符集/语言特定编码的最简单方法是:
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: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
中的默认管道。它非常简单直接。管道将作为控制的某种反转处理,最终的编码器实现必须处理Charset和语言特定的转换。这种解决方法已经剩下了许多测试。
EG注入默认管道:
this . pipeline (
/* string: */ str . toLowerCase ( ) ,
/* normalize: */ false ,
/* split: */ split ,
/* collapse: */ false
) ;
使用上面的管道架构来了解迭代和编码和后编码的差异。 STEMMER和MATCHERS需要在Charset归一化后(但语言转换之前)应用。
这是扩展管道的一个很好的例子: src/lang/latin/extra.js
→ src/lang/latin/advanced.js
→ src/lang/latin/simple.js
。
在src/lang/
中搜索您的语言,如果存在,则可以扩展或提供变体(例如方言/语)。如果该语言不存在,则创建一个新文件,并检查是否有任何现有的charset(例如拉丁语)适合您的语言。当不存在字符集时,您需要提供一个字符,作为语言的基础。
一个新的炭藏应该至少应提供:
encode
一个函数,该函数将传递的文本内容(删除特殊字符,舌头转换等)的字符归一化,并返回一系列分开的单词。还需要在此处应用Stemmer,Matcher或StopWord过滤器。当语言没有单词确保提供类似的东西时,例如每个中文标志也可能是“单词”。不要在没有分裂的情况下返回整个文本内容。rtl
布尔旗,指示左右编码基本上,Charset需要仅提供编码器功能以及用于左右编码的指标:
export function encode ( str ) { return [ str ] }
export const rtl = false ;
参考字符串: “Björn-Phillipp Mayer”
询问 | 默认 | 简单的 | 先进的 | 额外的 |
比约恩 | 是的 | 是的 | 是的 | 是的 |
比约尔 | 是的 | 是的 | 是的 | 是的 |
比约恩 | 不 | 是的 | 是的 | 是的 |
比约恩 | 不 | 不 | 是的 | 是的 |
菲利普 | 不 | 不 | 是的 | 是的 |
菲利普 | 不 | 不 | 是的 | 是的 |
Björnphillip | 不 | 是的 | 是的 | 是的 |
梅尔 | 不 | 不 | 是的 | 是的 |
BjörnMeier | 不 | 不 | 是的 | 是的 |
Meier Fhilip | 不 | 不 | 是的 | 是的 |
byorn mair | 不 | 不 | 不 | 是的 |
(误报) | 不 | 不 | 不 | 是的 |
以下示例完全索引了《格列佛的旅行斯威夫特·乔纳森1726》。
最有意义的有意义的设置只能为整本书分配1.2 MB!这可能是您将从搜索库中获得的最微小的内存足迹。
import { encode } from "./lang/latin/extra.js" ;
index = new Index ( {
encode : encode ,
tokenize : "strict" ,
optimize : true ,
resolution : 1 ,
minlength : 3 ,
fastupdate : false ,
context : false
} ) ;
这本测试的书《格列佛的旅行》(Swift Jonathan 1726)被完全索引:
默认情况下,词汇索引很小:
depth: 0, bidirectional: 0, resolution: 3, minlength: 0
=> 2.1 Mb
更高的分辨率将增加内存分配:
depth: 0, bidirectional: 0, resolution: 9, minlength: 0
=> 2.9 Mb
使用上下文索引将增加内存分配:
depth: 1, bidirectional: 0, resolution: 9, minlength: 0
=> 12.5 Mb
更高的上下文深度将增加内存分配:
depth: 2, bidirectional: 0, resolution: 9, minlength: 0
=> 21.5 Mb
较高的最小程度将减少内存分配:
depth: 2, bidirectional: 0, resolution: 9, minlength: 3
=> 19.0 mb
使用双向将减少内存分配:
depth: 2, bidirectional: 1, resolution: 9, minlength: 3
=> 17.9 Mb
启用选项“ fastupdate”将增加内存分配:
depth: 2, bidirectional: 1, resolution: 9, minlength: 3
=> 6.3 Mb
每个搜索库一直与这4个属性竞争:
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 |
商店:[fields] | +1(每个字段) | 0 | 0 | 0 |
缓存:真 | +10 | +10 | 0 | 0 |
缓存:100 | +1 | +9 | 0 | 0 |
ID的类型:编号 | 0 | 0 | 0 | 0 |
ID的类型:字符串 | +3 | -3 | 0 | 0 |
memory
(主要优化内存)performance
(主要优化性能)match
(主要优化以匹配)score
(主要优化得分)default
(默认平衡配置文件)这些轮廓涵盖了标准用例。建议应用自定义配置,而不是使用配置文件来为您的情况获得最佳状态。每个配置文件都可以进一步优化其特定任务,例如极端性能优化配置或极端内存等。
您可以在索引的创建/初始化期间通过预设。
在将内容添加到索引时,建议使用数字ID值作为参考。传递ID的字节长度显着影响记忆消耗。如果不可能,您应该考虑使用索引表并用索引映射ID,这变得很重要,尤其是在使用大量内容上的上下文索引时。
只要您可以,尝试将内容除以类别,并将其添加到其自己的索引中,例如:
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许可证下发布