loilo / fuse
基于 Bitap 算法的 PHP 模糊搜索
Requires
- php: ^7.4 || ^8.0
Requires (Dev)
- dms/phpunit-arraysubset-asserts: ^0.3.0 || ^0.4.0 || ^0.5.0
- phpunit/phpunit: ^8.0 || ^9.0
- psalm/plugin-phpunit: ^0.16.1 || ^0.17.0 || ^0.18.0
- squizlabs/php_codesniffer: ^3.6
- vimeo/psalm: ^4.9 || ^5.0
This package is auto-updated.
Last update: 2024-09-11 06:15:50 UTC
README
Fuse
PHP 的模糊搜索库
这是一个优秀项目 Fuse.js 的 PHP 版本,并尽可能提供完整的 API 兼容性。
最新兼容的 Fuse.js 版本:7.0.0
目录
安装
此包可通过 Composer 获取。要将它添加到您的项目中,只需运行
composer require loilo/fuse
注意,使用 Fuse 至少需要 PHP 7.4。
使用
以下是一个简单的使用示例
<?php require_once 'vendor/autoload.php'; $list = [ [ 'title' => "Old Man's War", 'author' => 'John Scalzi', ], [ 'title' => 'The Lock Artist', 'author' => 'Steve Hamilton', ], [ 'title' => 'HTML5', 'author' => 'Remy Sharp', ], [ 'title' => 'Right Ho Jeeves', 'author' => 'P.D Woodhouse', ], ]; $options = [ 'keys' => ['title', 'author'], ]; $fuse = new \Fuse\Fuse($list, $options); $fuse->search('hamil');
这将导致以下结果(其中每个结果中的 item
指的是匹配的条目本身,而 refIndex
提供了项目在原始 $list
中的位置)
[ [ 'item' => [ 'title' => 'The Lock Artist', 'author' => 'Steve Hamilton', ], 'refIndex' => 1, ], [ 'item' => [ 'title' => 'HTML5', 'author' => 'Remy Sharp', ], 'refIndex' => 2, ], ];
选项
Fuse 有很多选项可以细化您的搜索
基本选项
isCaseSensitive
- 类型:
bool
- 默认:
false
表示比较是否应该区分大小写。
includeScore
- 类型:
bool
- 默认:
false
是否应在结果集中包含分数。分数为 0
表示完美匹配,分数为 1
表示完全不匹配。
includeMatches
- 类型:
bool
- 默认:
false
是否应在结果集中包含匹配项。当 true
时,结果集中的每条记录将包括匹配字符的索引。这些可以相应地用于突出显示目的。
minMatchCharLength
- 类型:
int
- 默认:
1
只有长度超过此值的匹配才会被返回。(例如,如果您想忽略结果中的单字符匹配,将其设置为 2
)。
shouldSort
- 类型:
bool
- 默认:
true
是否按分数排序结果列表。
findAllMatches
- 类型:
bool
- 默认:
false
当为 true 时,即使字符串中已经找到完美匹配,匹配函数也会继续到搜索模式的末尾。
keys
- 类型:
array
- 默认:
[]
要搜索的键的列表。这支持嵌套路径、加权搜索、在 字符串 和 对象 数组中进行搜索。
模糊匹配选项
location
- 类型:
int
- 默认:
0
确定模式预期在文本中的位置。
threshold
- 类型:
float
- 默认:
0.6
匹配算法何时放弃。阈值为 0.0
需要完美匹配(包括字母和位置),阈值为 1.0
将匹配任何内容。
distance
- 类型:
int
- 默认:
100
确定匹配必须接近于模糊位置(由 location
指定)。如果字母匹配与模糊位置相距 distance
个字符,则计分为完全不匹配。如果 distance
为 0
,则匹配必须位于指定的 location
。如果 distance
为 1000
,则要求完美匹配必须位于 location
的 800
个字符内,以使用 threshold
为 0.8
。
ignoreLocation
- 类型:
bool
- 默认:
false
当 true
时,搜索将忽略 location
和 distance
,因此字符串中模式出现的任何位置都不会影响。
提示: 默认选项仅搜索前60个字符。如果合理地预计匹配在范围内,则这应该足够。要修改此行为,设置合适的
location
、threshold
、distance
(或ignoreLocation
)组合。为了更好地理解这些选项如何协同工作,请阅读有关 Fuse.js评分理论 的内容。
高级选项
useExtendedSearch
- 类型:
bool
- 默认:
false
当 true
时,它启用使用类似Unix的搜索命令。请参阅 示例。
getFn
- 类型:
callable
- 默认: 源
用于检索对象在提供的路径上值的函数。默认还将搜索嵌套路径。
sortFn
- 类型:
callable
- 默认: 源
用于对所有结果进行排序的函数。默认按相关性分数升序、索引升序排序。
ignoreFieldNorm
- 类型:
bool
- 默认:
false
当 true
时,用于相关性分数(用于排序)的计算将忽略 字段长度范数。
提示: 只有在字段的数量不重要,但查询项存在时,才应该将
ignoreFieldNorm
设置为true
。
fieldNormWeight
- 类型:
float
- 默认:
1
确定字段长度范数对评分的影响程度。值为 0
等同于忽略字段长度范数。值为 0.5
将大大减少字段长度范数的影响,而值为 2.0
将大大增加其影响。
全局配置
您可以通过 config
方法访问和操作所有上述选项的默认值。
// Get an associative array of all options listed above Fuse::config(); // Merge associative array of options into default config Fuse::config(['shouldSort' => false]); // Get single default option Fuse::config('shouldSort'); // Set single default option Fuse::config('shouldSort', false);
方法
以下方法在每个 Fuse\Fuse
实例上可用
search
搜索整个文档集合,并返回搜索结果列表。
public function search(mixed $pattern, ?array $options): array
参数 $pattern
可以是以下之一
参数 $options
limit
(类型:int
):表示返回的搜索结果的最大数量。
setCollection
设置/替换整个文档集合。如果没有提供索引,将生成一个。
public function setCollection(array $docs, ?\Fuse\Core\FuseIndex $index): void
示例
$fruits = ['apple', 'orange']; $fuse = new Fuse($fruits); $fuse->setCollection(['banana', 'pear']);
add
向集合添加文档并相应地更新索引。
public function add(mixed $doc): void
示例
$fruits = ['apple', 'orange']; $fuse = new Fuse($fruits); $fuse->add('banana'); sizeof($fruits); // => 3
remove
移除所有由谓词返回真值的文档,并返回被移除的文档数组。谓词使用两个参数调用: ($doc, $index)
。
public function remove(?callable $predicate): array
示例
$fruits = ['apple', 'orange', 'banana', 'pear']; $fuse = new Fuse($fruits); $results = $fuse->remove(fn($doc) => $doc === 'banana' || $doc === 'pear'); sizeof($fuse->getCollection()); // => 2 $results; // => ['banana', 'pear']
removeAt
移除指定索引处的文档。
public function removeAt(int $index): void
示例
$fruits = ['apple', 'orange', 'banana', 'pear']; $fuse = new Fuse($fruits); $fuse->removeAt(1); $fuse->getCollection(); // => ['apple', 'banana', 'pear']
getIndex
返回生成的Fuse索引。
public function getIndex(): \Fuse\Core\FuseIndex
示例
$fruits = ['apple', 'orange', 'banana', 'pear']; $fuse = new Fuse($fruits); $fuse->getIndex()->size(); // => 4
索引
以下方法在每个 Fuse\Fuse
实例上可用
Fuse::createIndex
从列表预先生成索引并将其直接传递到Fuse实例。如果列表(相当)大,则可以提高实例化速度。
public static function createIndex(array $keys, array $docs, array $options = []): \Fuse\Core\FuseIndex
示例
$list = [ ... ]; // See the example from the 'Usage' section $options = [ 'keys' => [ 'title', 'author.firstName' ] ]; // Create the Fuse index $myIndex = Fuse::createIndex($options['keys'], $list); // Initialize Fuse with the index $fuse = new Fuse($list, $options, $myIndex);
Fuse::parseIndex
解析JSON序列化的Fuse索引。
public static function parseIndex(array $data, array $options = []): \Fuse\Core\FuseIndex
示例
// (1) When the data is collected $list = [ ... ]; // See the example from the 'Usage' section $options = [ 'keys' => [ 'title', 'author.firstName' ] ]; // Create the Fuse index $myIndex = Fuse::createIndex($options['keys'], $list); // Serialize and save it file_put_contents('fuse-index.json', json_encode($myIndex)); // (2) When the search is needed // Load and deserialize index to an array $fuseIndex = json_decode(file_get_contents('fuse-index.json'), true); $myIndex = Fuse::parseIndex($fuseIndex); // Initialize Fuse with the index $fuse = new Fuse($list, $options, $myIndex);
与 Fuse.js 的区别
开发
项目范围
请注意,我正在努力与Fuse.js保持功能一致性,因此不会添加Fuse.js本身未反映的搜索逻辑功能或修复。
如果您在使用这个PHP端口搜索结果时遇到的问题不是显然的bug,并且您恰好了解JavaScript,请检查您的用例是否在Fuse.js在线演示中正确运行,因为那是规范化的Fuse实现。如果问题同样出现在那里,请在他们的仓库中提交一个问题。
设置
要开始开发Fuse,您需要git、PHP(≥ 7.4)和Composer。
克隆仓库并进入
git clone https://github.com/loilo/fuse.git
cd fuse
安装Composer依赖项
composer install
安装npm依赖项(可选但推荐)。这仅用于代码格式化,因为npm依赖项包括本项目使用的Prettier插件。
npm ci
质量保证
本项目有不同种类的代码检查。所有这些检查在提交拉取请求时都会运行,也可以在本地运行。
贡献
在提交拉取请求之前,请向test
文件夹添加相关测试。