Parser, serializer, dan mesin pencari seperti Lucene yang ringan dan berperforma tinggi.
Liqe awalnya dibuat untuk mengaktifkan pemfilteran log Roarr melalui cli. Saya telah memoles proyek ini sebagai hobi/latihan intelektual. Saya telah melihatnya diadopsi oleh berbagai CLI dan aplikasi web yang memerlukan pencarian lanjutan. Sepengetahuan saya, saat ini merupakan parser dan serializer sintaksis mirip Lucene terlengkap dalam JavaScript, serta mesin pencari dalam memori yang kompatibel.
Kasus penggunaan cairan meliputi:
Perhatikan bahwa Liqe AST diperlakukan sebagai API publik, yaitu seseorang dapat mengimplementasikan mekanisme pencariannya sendiri yang menggunakan bahasa kueri 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 koleksi:
filter ( parse ( 'height:>170' ) , persons ) ;
// [
// {
// height: 180,
// name: 'John Morton',
// },
// {
// height: 175,
// name: 'David Barker',
// },
// ]
Uji satu objek:
test ( parse ( 'name:John' ) , persons [ 0 ] ) ;
// true
test ( parse ( 'name:David' ) , persons [ 0 ] ) ;
// false
Sorot bidang dan substring yang cocok:
highlight ( parse ( 'name:john' ) , persons [ 0 ] ) ;
// [
// {
// path: 'name',
// query: /(John)/,
// }
// ]
highlight ( parse ( 'height:180' ) , persons [ 0 ] ) ;
// [
// {
// path: 'height',
// }
// ]
Liqe menggunakan Liqe Query Language (LQL), yang sangat terinspirasi oleh Lucene tetapi mengembangkannya dalam berbagai cara yang memungkinkan pengalaman pencarian yang lebih hebat.
# 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 )
Cari kata "foo" di bidang apa pun (tidak peka huruf besar-kecil).
foo
Cari kata "foo" di kolom name
.
name :foo
Cari nilai bidang name
yang cocok dengan /foo/i
regex.
name :/foo / i
Cari nilai bidang name
yang cocok dengan pola wildcard f*o
.
name :f * o
Cari nilai bidang name
yang cocok f?o
pola wildcard.
name :f? o
Cari frasa "foo bar" di kolom name
(peka huruf besar/kecil).
name :"foo bar"
Cari nilai yang sama dengan 100 di bidang height
.
height : = 100
Cari nilai yang lebih besar dari 100 di bidang height
.
height :>100
Cari nilai yang lebih besar atau sama dengan 100 di bidang height
.
height :>=100
Cari nilai yang lebih besar atau sama dengan 100 dan lebih rendah atau sama dengan 200 di bidang height
.
height : [ 100 TO 200 ]
Cari nilai yang lebih besar dari 100 dan lebih rendah dari 200 di bidang height
.
height : { 100 TO 200 }
Cari kata apa pun yang dimulai dengan "foo" di kolom name
.
name :foo *
Cari kata apa pun yang dimulai dengan "foo" dan diakhiri dengan "bar" di kolom name
.
name :foo * bar
Cari kata apa pun yang dimulai dengan "foo" di kolom name
, diikuti dengan satu karakter arbitrer.
name :foo?
Cari kata apa pun yang dimulai dengan "foo", diikuti dengan satu karakter arbitrer dan segera diakhiri dengan "bar" di kolom name
.
name :foo? bar
Cari frasa "foo bar" di kolom name
DAN frasa "quick fox" di kolom bio
.
name :"foo bar" AND bio : "quick fox"
Cari frasa "foo bar" di kolom name
DAN frasa "quick fox" di kolom bio
, atau kata "fox" di kolom name
.
( name :"foo bar" AND bio : "quick fox" ) OR name : fox
Serializer memungkinkan untuk mengonversi token Liqe kembali ke permintaan pencarian asli.
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' ;
Ada 11 token AST yang menggambarkan kueri Liqe yang diurai.
Jika Anda membuat serializer, Anda harus mengimplementasikan semuanya untuk mencakup semua kemungkinan input kueri secara lengkap. Lihat serializer bawaan untuk contohnya.
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 ;
Kemampuan Lucene berikut tidak didukung:
Jika terjadi kesalahan sintaksis, Liqe menampilkan 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 ;
}
}
Pertimbangkan untuk menggunakan paket highlight-words
untuk menyorot kecocokan Liqe.
Jika Anda akan memodifikasi parser, gunakan npm run watch
untuk menjalankan kompiler dalam mode tontonan.
Sebelum melakukan perubahan apa pun, catat benchmark saat ini di mesin Anda menggunakan npm run benchmark
. Jalankan benchmark lagi setelah melakukan perubahan apa pun. Sebelum melakukan perubahan, pastikan kinerja tidak terkena dampak negatif.