가볍고 성능이 뛰어난 Lucene과 유사한 파서, 직렬 변환기 및 검색 엔진입니다.
원래 Liqe는 cli를 통해 Roarr 로그 필터링을 활성화하도록 구축되었습니다. 나는 그 이후로 이 프로젝트를 취미/지적 활동으로 다듬어 왔습니다. 고급 검색이 필요한 다양한 CLI 및 웹 애플리케이션에서 이 기능을 채택하는 것을 보았습니다. 내가 아는 바로는 현재 JavaScript에서 가장 완벽한 Lucene 유사 구문 분석기 및 직렬 변환기이자 호환 가능한 메모리 내 검색 엔진입니다.
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는 Lucene에서 크게 영감을 받았지만 보다 강력한 검색 경험을 허용하는 다양한 방식으로 확장하는 Liqe 쿼리 언어(LQL)를 사용합니다.
# 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"로 시작하고 그 뒤에 임의의 문자 하나가 오는 단어를 검색합니다.
name :foo?
name
필드에서 "foo"로 시작하고 그 뒤에 임의의 단일 문자가 오고 즉시 "bar"로 끝나는 모든 단어를 검색합니다.
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 쿼리를 설명하는 11개의 AST 토큰이 있습니다.
직렬 변환기를 구축하는 경우 가능한 모든 쿼리 입력을 완벽하게 처리하려면 직렬 변환기를 모두 구현해야 합니다. 예제는 내장 직렬 변환기를 참조하세요.
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
사용하여 컴퓨터의 현재 벤치마크를 캡처하세요. 변경 후 벤치마크를 다시 실행하세요. 변경 사항을 커밋하기 전에 성능에 부정적인 영향이 없는지 확인하세요.