Analizador, serializador y motor de búsqueda ligero y eficaz similar a Lucene.
Liqe se creó originalmente para habilitar el filtrado de registros de Roarr a través de cli. Desde entonces he ido puliendo este proyecto como hobby/ejercicio intelectual. Lo he visto adoptado por varias CLI y aplicaciones web que requieren búsqueda avanzada. Hasta donde yo sé, actualmente es el analizador y serializador de sintaxis similar a Lucene en JavaScript más completo, así como un motor de búsqueda en memoria compatible.
Los casos de uso similares incluyen:
Tenga en cuenta que Liqe AST se trata como una API pública, es decir, uno podría implementar su propio mecanismo de búsqueda que utilice el lenguaje de consulta 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' ,
} ,
] ;
Filtrar una colección:
filter ( parse ( 'height:>170' ) , persons ) ;
// [
// {
// height: 180,
// name: 'John Morton',
// },
// {
// height: 175,
// name: 'David Barker',
// },
// ]
Pruebe un solo objeto:
test ( parse ( 'name:John' ) , persons [ 0 ] ) ;
// true
test ( parse ( 'name:David' ) , persons [ 0 ] ) ;
// false
Resalte campos y subcadenas coincidentes:
highlight ( parse ( 'name:john' ) , persons [ 0 ] ) ;
// [
// {
// path: 'name',
// query: /(John)/,
// }
// ]
highlight ( parse ( 'height:180' ) , persons [ 0 ] ) ;
// [
// {
// path: 'height',
// }
// ]
Liqe utiliza Liqe Query Language (LQL), que está fuertemente inspirado en Lucene pero lo amplía de varias maneras que permiten una experiencia de búsqueda más poderosa.
# 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 )
Busque la palabra "foo" en cualquier campo (no distingue entre mayúsculas y minúsculas).
foo
Busque la palabra "foo" en el campo name
.
name :foo
Busque valores de campo name
que coincidan con /foo/i
regex.
name :/foo / i
Busque valores de campo name
que coincidan con el patrón comodín f*o
.
name :f * o
Busque valores de campo name
que coincidan f?o
patrón de comodín.
name :f? o
Busque la frase "foo bar" en el campo name
(distingue entre mayúsculas y minúsculas).
name :"foo bar"
Busque un valor igual a 100 en el campo height
.
height : = 100
Busque un valor mayor que 100 en el campo height
.
height :>100
Busque un valor mayor o igual a 100 en el campo height
.
height :>=100
Busque valor mayor o igual a 100 e inferior o igual a 200 en el campo height
.
height : [ 100 TO 200 ]
Busque un valor mayor que 100 y menor que 200 en el campo height
.
height : { 100 TO 200 }
Busque cualquier palabra que comience con "foo" en el campo name
.
name :foo *
Busque cualquier palabra que comience con "foo" y termine con "bar" en el campo name
.
name :foo * bar
Busque cualquier palabra que comience con "foo" en el campo name
, seguida de un único carácter arbitrario.
name :foo?
Busque cualquier palabra que comience con "foo", seguida de un único carácter arbitrario y que termine inmediatamente con "bar" en el campo name
.
name :foo? bar
Busque la frase "foo bar" en el campo name
Y la frase "quick fox" en el campo bio
.
name :"foo bar" AND bio : "quick fox"
Busque la frase "foo bar" en el campo name
Y la frase "quick fox" en el campo bio
, o la palabra "fox" en el campo name
.
( name :"foo bar" AND bio : "quick fox" ) OR name : fox
El serializador permite convertir tokens Liqe a la consulta de búsqueda original.
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' ;
Hay 11 tokens AST que describen una consulta Liqe analizada.
Si está creando un serializador, debe implementarlos todos para una cobertura completa de todas las entradas de consulta posibles. Consulte el serializador incorporado para ver un ejemplo.
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 ;
Las siguientes habilidades de Lucene no son compatibles:
En caso de un error de sintaxis, Liqe arroja 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 ;
}
}
Considere usar el paquete de highlight-words
para resaltar las coincidencias de Liqe.
Si va a modificar el analizador, utilice npm run watch
para ejecutar el compilador en modo de vigilancia.
Antes de realizar cualquier cambio, capture el punto de referencia actual en su máquina usando npm run benchmark
. Ejecute el punto de referencia nuevamente después de realizar cualquier cambio. Antes de realizar cambios, asegúrese de que el rendimiento no se vea afectado negativamente.