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
に一致する必要があります。距離が1000
の場合、 threshold
0.8
を使用して検索されるlocation
の800
文字以内に完全一致が存在する必要があります。
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 );
次のメソッドは、各FuseFuse
インスタンスで使用できます。
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
述語が真実を返すすべてのドキュメントをリストから削除し、削除されたドキュメントの配列を返します。述語は 2 つの引数($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
次のメソッドは、各FuseFuse
インスタンスで使用できます。
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 | PHP ヒューズ | |
---|---|---|
ヒューズのバージョンを取得する | Fuse.version | – |
グローバル構成にアクセスする | Fuse.config プロパティ | Fuse::config メソッド |
リストの変更 | fuse.add() などを使用すると、 new Fuse コンストラクターに渡される元のリストが変更されます。 | PHP では、配列はプリミティブ データ型です。つまり、元のリストが Fuse によって変更されることはありません。項目の追加/削除後に現在のリストを受け取るには、 $fuse->getCollection() メソッドを使用できます。 |
私は Fuse.js と同等の機能を目指しているため、Fuse.js 自体に反映されていない機能や修正は検索ロジックに追加しないことに注意してください。
この PHP ポートで明らかにバグではない検索結果の問題があり、JavaScript の知識がある場合は、正規の Fuse 実装である Fuse.js のオンライン デモでユースケースが正しく動作するかどうかを確認してください。そこでも問題が発生する場合は、リポジトリで問題を開いてください。
Fuse で開発を開始するには、git、PHP (≥ 7.4)、および Composer が必要です。
コードは Prettier を使用してフォーマットされるため、Node.js/npm をインストールし、Prettier フォーマットをサポートするエディターを使用することもお勧めします。
リポジトリのクローンを作成し、それにcd
します。
git clone https://github.com/loilo/fuse.git
cd fuse
Composer の依存関係をインストールします。
composer install
npm 依存関係をインストールします (オプションですが推奨)。 npm の依存関係にはこのプロジェクトで使用される Prettier プラグインが含まれるため、これはコードのフォーマットにのみ必要です。
npm ci
このプロジェクトにはさまざまな種類のコード チェックが用意されています。これらはすべて、プル リクエストの送信時に実行されますが、ローカルで実行することもできます。
指示 | 目的 | 説明 |
---|---|---|
vendor/bin/phpcs | コードスタイルをチェックする | PHP_CodeSniffer を実行して、Fuse ソース コードが PSR-12 コーディング スタイルに従っていることを確認します。 |
vendor/bin/psalm | 静的解析 | コードベースに対して Psalm を実行して、型関連のエラーや安全でないコーディング パターンを回避します。 |
vendor/bin/phpunit | プログラムロジックをチェックする | test フォルダーからすべての PHPUnit テストを実行します。 |
プル リクエストを送信する前に、関連するテストをtest
フォルダーに追加してください。