軽量でパフォーマンスの高い Lucene のようなパーサー、シリアライザー、および検索エンジン。
もともと Liqe は、cli 経由で Roarr ログ フィルタリングを有効にするために構築されました。それ以来、私は趣味/知的な練習としてこのプロジェクトに磨きをかけてきました。高度な検索を必要とするさまざまな CLI や Web アプリケーションでこれが採用されているのを見てきました。私の知る限り、これは現在最も完全な Lucene に似た JavaScript の構文パーサーおよびシリアライザーであり、互換性のあるメモリ内検索エンジンでもあります。
Liqe の使用例は次のとおりです。
Liqe AST はパブリック API として扱われることに注意してください。つまり、Liqe クエリ言語 (LQL) を使用する独自の検索メカニズムを実装できます。
import {
filter ,
highlight ,
parse ,
test ,
} from 'liqe' ;
const persons = [
{
height : 180 ,
name : 'John Morton' ,
} ,
{
height : 175 ,
name : 'David Barker' ,
} ,
{
height : 170 ,
name : 'Thomas Castro' ,
} ,
] ;
コレクションをフィルタリングします。
filter ( parse ( 'height:>170' ) , persons ) ;
// [
// {
// height: 180,
// name: 'John Morton',
// },
// {
// height: 175,
// name: 'David Barker',
// },
// ]
単一のオブジェクトをテストします。
test ( parse ( 'name:John' ) , persons [ 0 ] ) ;
// true
test ( parse ( 'name:David' ) , persons [ 0 ] ) ;
// false
一致するフィールドと部分文字列を強調表示します。
highlight ( parse ( 'name:john' ) , persons [ 0 ] ) ;
// [
// {
// path: 'name',
// query: /(John)/,
// }
// ]
highlight ( parse ( 'height:180' ) , persons [ 0 ] ) ;
// [
// {
// path: 'height',
// }
// ]
Liqe は、Liqe クエリ言語 (LQL) を使用します。LQL は、Lucene から多大な影響を受けていますが、より強力な検索エクスペリエンスを可能にするさまざまな方法でそれを拡張しています。
# search for "foo" term anywhere in the document (case insensitive)
foo
# search for "foo" term anywhere in the document (case sensitive)
'foo'
"foo"
# search for "foo" term in `name` field
name :foo
# search for "foo" term in `full name` field
'full name' : foo
"full name" : foo
# search for "foo" term in `first` field, member of `name`, i.e.
# matches {name: {first: 'foo'}}
name . first :foo
# search using regex
name :/foo /
name :/ foo / o
# search using wildcard
name :foo * bar
name :foo? bar
# boolean search
member :true
member :false
# null search
member :null
# search for age =, >, >=, <, <=
height : = 100
height :>100
height :>=100
height :<100
height :<=100
# search for height in range (inclusive, exclusive)
height : [ 100 TO 200 ]
height : { 100 TO 200 }
# boolean operators
name :foo AND height : = 100
name :foo OR name : bar
# unary operators
NOT foo
- foo
NOT foo : bar
- foo :bar
name :foo AND NOT ( bio :bar OR bio : baz )
# implicit AND boolean operator
name :foo height : = 100
# grouping
name :foo AND ( bio :bar OR bio : baz )
任意のフィールドで単語「foo」を検索します (大文字と小文字は区別されません)。
foo
name
フィールドで単語「foo」を検索します。
name :foo
/foo/i
正規表現に一致するname
フィールド値を検索します。
name :/foo / i
f*o
ワイルドカード パターンに一致するname
フィールド値を検索します。
name :f * o
f?o
ワイルドカード パターンに一致するname
フィールド値を検索します。
name :f? o
name
フィールドでフレーズ「foo bar」を検索します (大文字と小文字が区別されます)。
name :"foo bar"
height
フィールドで 100 に等しい値を検索します。
height : = 100
height
フィールドで 100 を超える値を検索します。
height :>100
height
フィールドで 100 以上の値を検索します。
height :>=100
height
フィールドで 100 以上 200 以下の値を検索します。
height : [ 100 TO 200 ]
height
フィールドで 100 より大きく 200 より小さい値を検索します。
height : { 100 TO 200 }
name
フィールドで「foo」で始まる単語を検索します。
name :foo *
name
フィールドで「foo」で始まり「bar」で終わる単語を検索します。
name :foo * bar
name
フィールドで「foo」で始まり、その後に任意の 1 文字が続く単語を検索します。
name :foo?
「foo」で始まり、その後に任意の 1 文字が続き、すぐに「bar」で終わる単語をname
フィールドで検索します。
name :foo? bar
name
フィールドで「foo bar」というフレーズを検索し、 bio
フィールドで「quick fox」というフレーズを検索します。
name :"foo bar" AND bio : "quick fox"
name
フィールドの語句「foo bar」とbio
フィールドの語句「quick fox」、またはname
フィールドの語句「fox」のいずれかを検索します。
( name :"foo bar" AND bio : "quick fox" ) OR name : fox
シリアライザーを使用すると、Liqe トークンを元の検索クエリに変換できます。
import {
parse ,
serialize ,
} from 'liqe' ;
const tokens = parse ( 'foo:bar' ) ;
// {
// expression: {
// location: {
// start: 4,
// },
// quoted: false,
// type: 'LiteralExpression',
// value: 'bar',
// },
// field: {
// location: {
// start: 0,
// },
// name: 'foo',
// path: ['foo'],
// quoted: false,
// type: 'Field',
// },
// location: {
// start: 0,
// },
// operator: {
// location: {
// start: 3,
// },
// operator: ':',
// type: 'ComparisonOperator',
// },
// type: 'Tag',
// }
serialize ( tokens ) ;
// 'foo:bar'
import {
type BooleanOperatorToken ,
type ComparisonOperatorToken ,
type EmptyExpression ,
type FieldToken ,
type ImplicitBooleanOperatorToken ,
type ImplicitFieldToken ,
type LiteralExpressionToken ,
type LogicalExpressionToken ,
type RangeExpressionToken ,
type RegexExpressionToken ,
type TagToken ,
type UnaryOperatorToken ,
} from 'liqe' ;
解析された Liqe クエリを記述する AST トークンが 11 個あります。
シリアライザーを構築している場合は、考えられるすべてのクエリ入力を完全にカバーするために、シリアライザーをすべて実装する必要があります。例については、組み込みシリアライザーを参照してください。
import {
isSafeUnquotedExpression ,
} from 'liqe' ;
/**
* Determines if an expression requires quotes.
* Use this if you need to programmatically manipulate the AST
* before using a serializer to convert the query back to text.
*/
isSafeUnquotedExpression ( expression : string ) : boolean ;
次の Lucene 機能はサポートされていません。
構文エラーの場合、Liqe はSyntaxError
をスローします。
import {
parse ,
SyntaxError ,
} from 'liqe' ;
try {
parse ( 'foo bar' ) ;
} catch ( error ) {
if ( error instanceof SyntaxError ) {
console . error ( {
// Syntax error at line 1 column 5
message : error . message ,
// 4
offset : error . offset ,
// 1
offset : error . line ,
// 5
offset : error . column ,
} ) ;
} else {
throw error ;
}
}
Liqe の一致を強調表示するには、 highlight-words
パッケージの使用を検討してください。
パーサーを変更する場合は、 npm run watch
使用してコンパイラーを監視モードで実行します。
変更を加える前に、 npm run benchmark
使用してマシン上の現在のベンチマークを取得します。変更を加えた後、ベンチマークを再度実行します。変更をコミットする前に、パフォーマンスに悪影響が及ばないことを確認してください。