From 89125f62a35b8c0ddd1160995cead950b71526e9 Mon Sep 17 00:00:00 2001 From: Thomas Wilkerling Date: Wed, 13 Feb 2019 13:14:26 +0100 Subject: [PATCH] v0.5.3 Logical Operator --- CHANGELOG.md | 4 + README.md | 22 ++++- dist/flexsearch.compact.js | 45 ++++----- dist/flexsearch.es5.js | 79 +++++++-------- dist/flexsearch.light.js | 25 ++--- dist/flexsearch.min.js | 66 ++++++------- dist/flexsearch.node.js | 58 +++++------ flexsearch.js | 140 ++++++++++++++++---------- package.json | 2 +- test/test.es6.js | 44 ++++----- test/test.js | 196 +++++++++++++++++++++++-------------- 11 files changed, 396 insertions(+), 285 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ea3929..1777e88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +#### v0.5.3 + +- Logical Operator + #### v0.5.2 - Intersect Partial Results diff --git a/README.md b/README.md index ecc5d32..28c2c26 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ Library Comparison: here how to enable. -FlexSearch introduce a new scoring mechanism called __Contextual Search__ which was invented by Thomas Wilkerling, the author of this library. A Contextual Search incredibly boost up queries to a complete new level but also requires some additionally memory (depending on ___depth___). +FlexSearch introduce a new scoring mechanism called __Contextual Search__ which was invented by Thomas Wilkerling, the author of this library. A Contextual Search incredibly boost up queries to a complete new level but also requires some additionally memory (depending on ___depth___). The basic idea of this concept is to limit relevance by its context instead of calculating relevance through the whole (unlimited) distance. In this way contextual search also improves the results of relevance-based queries on a large amount of text data. @@ -1275,10 +1275,13 @@ var results = index.search("foobar", { Search the same query on multiple fields: +> Using ___bool___ as a logical operator when searching through multiple fields. The default operator when not set is ___"and"___. It is planned to extend the concept of logical operators to make combinations of ___and___ / ___or___ / ___not___. + ```js var results = index.search({ query: "foobar", - field: ["title", "body"] + field: ["title", "body"], + bool: "or" }); ``` @@ -1286,7 +1289,8 @@ Could also be written as: ```js var results = index.search("title", { - field: ["title", "body"] + field: ["title", "body"], + bool: "or" }); ``` @@ -1295,13 +1299,16 @@ Search different queries on multiple fields: ```js var results = index.search([{ field: "title", - query: "foo" + query: "foo", + bool: "and" },{ field: "body", - query: "bar" + query: "bar", + bool: "and" }]); ``` + ## Find / Where @@ -2513,6 +2521,10 @@ node compile SUPPORT_WORKER=true +## Contribution + +I would be glad about any kind of help. Feel free to contribute to this project and also feel free to contact me (https://github.com/ts-thomas) when you have any questions. There are just one simple (and maybe unusual) coding convention: all public accessible identifiers should be singular. + Changelog --- diff --git a/dist/flexsearch.compact.js b/dist/flexsearch.compact.js index 2f81426..7662303 100644 --- a/dist/flexsearch.compact.js +++ b/dist/flexsearch.compact.js @@ -1,28 +1,29 @@ /* - FlexSearch v0.5.2 + FlexSearch v0.5.3 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(n,z,A){let x;(x=A.define)&&x.amd?x([],function(){return z}):(x=A.modules)?x[n.toLowerCase()]=z:"object"===typeof exports?module.exports=z:A[n]=z})("FlexSearch",function(){function n(b,a){const c=a?a.id:b&&b.id;this.id=c||0===c?c:T++;this.init(b,a);x(this,"index",function(){return this.f});x(this,"length",function(){return Object.keys(this.f).length})}function z(b,a){const c=b.length,d=E(a),f=[];for(let h=0,g=0;h=g&&(b=b[l-(f+.5>>0)],b=b[c]|| -(b[c]=[]),b[b.length]=d);return f}function K(b,a){if(b){const c=Object.keys(b);for(let d=0,f=c.length;db?1:b?-1:0}function V(b,a){b=b[v];a=a[v];return ba?1:0}function U(b,a){const c=v.length;for(let d=0;da?1:0}function N(b,a,c,d){c=[];let f;const h=b.length;if(1a&&(c=c.slice(0,a)));return c}function F(b){return"string"===typeof b}function w(b){return b.constructor===Array}function E(b){return"function"===typeof b}function C(b){return"object"===typeof b}function G(b){return"undefined"===typeof b}function O(b){const a= -Array(b);for(let c=0;ck;c--)m=g.substring(k,c),I(J,p,m,b,a,t,l,D-1)}break;default:if(e=I(J,p,g,b,1,t,l,D-1),n&&1=l)for(e=p._ctx[g]||(p._ctx[g]=u()),g=this.h[g]||(this.h[g]=O(D-(l||0))), -t=a-n,m=a+n+1,0>t&&(t=0),m>q&&(m=q);t=h&&(b=b[r-(f+.5>>0)],b=b[c]|| +(b[c]=[]),b[b.length]=d);return f}function J(b,a){if(b){const c=Object.keys(b);for(let d=0,f=c.length;db?1:b?-1:0}function W(b,a){b=b[x];a=a[x];return ba?1:0}function V(b,a){const c=x.length;for(let d=0;da?1:0}function M(b,a,c,d,f){d=[];let g;const h=b.length;if(1c&&(d=d.slice(0,c)));return d}function F(b){return"string"===typeof b}function y(b){return b.constructor===Array}function E(b){return"function"===typeof b}function D(b){return"object"=== +typeof b}function G(b){return"undefined"===typeof b}function P(b){const a=Array(b);for(let c=0;cm;c--)p=h.substring(m,c),I(u,l,p,b,a,n,r,k-1)}break;default:if(e=I(u,l,h,b,1,n,r,k-1),v&&1=r)for(e= +l._ctx[h]||(l._ctx[h]=w()),h=this.h[h]||(this.h[h]=P(k-(r||0))),n=a-v,p=a+v+1,0>n&&(n=0),p>q&&(p=q);n=g&&(this.F=this.i),this.F===this.i&&(this.cache&& -this.v.set(b,this.A),this.I&&this.I(this.A)));return this}function A(a,b){for(var c=a.length,g=M(b),k=[],p=0,e=0;p=e&&(a=a[f-(k+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=g);return k}function Q(a,b){if(a)for(var c=Object.keys(a),g=0,k=c.length;ga?1:a?-1:0}function da(a,b){a=a[G];b=b[G];return ab?1:0}function ea(a,b){for(var c=G.length,g=0;gb?1:0}function O(a,b,c,g){c=[];var k=a.length;if(1b&&(c=c.slice(0,b)));return c}function L(a){return"string"===typeof a}function I(a){return a.constructor=== -Array}function M(a){return"function"===typeof a}function K(a){return"object"===typeof a}function F(a){return"undefined"===typeof a}function U(a){for(var b=Array(a),c=0;c=this.b.length&&(this.w=0),this.b[this.w].postMessage({add:!0,id:a,content:b}),this.c[e]=""+this.w,c&&c(),this;if(!k){if(this.async&&"function"!==typeof importScripts){var f=this;e=new Promise(function(c){setTimeout(function(){f.add(a,b,null,g,!0);f=null;c()})});if(c)e.then(c);else return e;return this}if(c)return this.add(a,b,null,g,!0),c(),this}b= -this.encode(b);if(!b.length)return this;c=this.h;k=M(c)?c(b):b.split(W);this.filter&&(k=A(k,this.filter));var d=C();d._ctx=C();for(var h=k.length,r=this.threshold,q=this.depth,n=this.f,m=this.o,v=this.H,B=0;B -w;z--)E=y.substring(w,z),H(m,d,E,a,t,D,r,n-1);break;default:if(x=H(m,d,y,a,1,D,r,n-1),q&&1=r)for(x=d._ctx[y]||(d._ctx[y]=C()),y=this.u[y]||(this.u[y]=U(n-(r||0))),D=B-q,E=B+q+1,0>D&&(D=0),E>h&&(E=h);Df;d--)m=h[d- -1],h[d]=m,e[m]=d;h[f]=a;e[a]=f}}}return b};return a}();return f}(function(){var h={},l="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(f,m,A,J,d){A=l?URL.createObjectURL(new Blob(["("+A.toString()+")()"],{type:"text/javascript"})):f+".es5.js";f+="-"+m;h[f]||(h[f]=[]);h[f][d]=new Worker(A);h[f][d].onmessage=J;console.log("Register Worker: "+f+"@"+d);return h[f][d]}}()),this); +'use strict';function aa(h){var n=0;return function(){return n=g&&(this.F=this.i),this.F===this.i&&(this.cache&& +this.v.set(b,this.A),this.I&&this.I(this.A)));return this}function A(a,b){for(var c=a.length,g=M(b),k=[],m=0,e=0;m=e&&(a=a[f-(k+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=g);return k}function L(a,b){if(a)for(var c=Object.keys(a),g=0,k=c.length;ga?1:a?-1:0}function ea(a,b){a=a[F];b=b[F];return ab?1:0}function fa(a,b){for(var c=F.length,g=0;gb?1:0}function O(a,b,c,g,k){g=[];var m=a.length;if(1 +c&&(g=g.slice(0,c)));return g}function K(a){return"string"===typeof a}function G(a){return a.constructor===Array}function M(a){return"function"===typeof a}function J(a){return"object"===typeof a}function C(a){return"undefined"===typeof a}function V(a){for(var b=Array(a),c=0;c=this.b.length&&(this.w=0),this.b[this.w].postMessage({add:!0,id:a,content:b}),this.c[m]=""+this.w,c&&c(),this;if(!e){if(this.async&&"function"!==typeof importScripts){var f=this;m=new Promise(function(c){setTimeout(function(){f.add(a, +b,null,g,!0);f=null;c()})});if(c)m.then(c);else return m;return this}if(c)return this.add(a,b,null,g,!0),c(),this}b=this.encode(b);if(!b.length)return this;c=this.h;e=M(c)?c(b):b.split(X);this.filter&&(e=A(e,this.filter));var k=D();k._ctx=D();for(var d=e.length,h=this.threshold,l=this.depth,p=this.f,P=this.o,x=this.H,q=0;qv;r--)z=B.substring(v,r),E(P,k,z,a,t,w,h,p-1);break;default:if(y=E(P,k,B,a,1,w,h,p-1),l&&1=h)for(y=k._ctx[B]||(k._ctx[B]=D()),B=this.u[B]||(this.u[B]=V(p-(h||0))),w=q-l,z=q+l+1,0>w&&(w=0),z>d&&(z=d);wf;d--)l=h[d-1],h[d]=l,e[l]=d;h[f]=a;e[a]=f}}}return b};return a}();return f}(function(){var h={},n="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(f,l,A,I,d){A=n?URL.createObjectURL(new Blob(["("+A.toString()+")()"],{type:"text/javascript"})):f+".es5.js";f+="-"+l;h[f]||(h[f]=[]);h[f][d]=new Worker(A);h[f][d].onmessage=I;console.log("Register Worker: "+f+"@"+ +d);return h[f][d]}}()),this); diff --git a/dist/flexsearch.light.js b/dist/flexsearch.light.js index 4bcbdb1..3bc375f 100644 --- a/dist/flexsearch.light.js +++ b/dist/flexsearch.light.js @@ -1,18 +1,19 @@ /* - FlexSearch v0.5.2 + FlexSearch v0.5.3 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(e,u,r){let l;(l=r.define)&&l.amd?l([],function(){return u}):(l=r.modules)?l[e.toLowerCase()]=u:"object"===typeof exports?module.exports=u:r[e]=u})("FlexSearch",function(){function e(a,c){const b=c?c.id:a&&a.id;this.id=b||0===b?b:I++;this.init(a,c);r(this,"index",function(){return this.b});r(this,"length",function(){return Object.keys(this.b).length})}function u(a,c){const b=a.length,f=x(c),d=[];for(let n=0,g=0;n=g&&(a=a[h-(d+.5>>0)],a=a[b]||(a[b]=[]),a[a.length]=f);return d}function C(a,c){if(a){const b=Object.keys(a);for(let f=0,d=b.length;fa?1:a?-1:0}function z(a){return"string"===typeof a}function x(a){return"function"===typeof a}function A(a){return"undefined"===typeof a}function E(a){const c=Array(a);for(let b=0;bk;c--)m=n.substring(k,c),y(B,f,m,a,b,h,v,q-1)}break;default:if(g=y(B,f,n,a,1,h,v,q-1),l&&1=v)for(g=f._ctx[n]||(f._ctx[n]=t()),n=this.f[n]||(this.f[n]=E(q-(v||0))),h=e-l,m=e+l+1,0>h&&(h=0),m>d&&(m=d);hc&&(g=g.slice(0,c)));e=g}return e};e.prototype.clear=function(){return this.destroy().init()};e.prototype.destroy=function(){this.h=this.f=this.b=null;return this};const w={icase:function(a){return a.toLowerCase()}};return e}(!1),this); +'use strict';(function(f,w,y){let m;(m=y.define)&&m.amd?m([],function(){return w}):(m=y.modules)?m[f.toLowerCase()]=w:"object"===typeof exports?module.exports=w:y[f]=w})("FlexSearch",function(){function f(a,c){const b=c?c.id:a&&a.id;this.id=b||0===b?b:M++;this.init(a,c);y(this,"index",function(){return this.b});y(this,"length",function(){return Object.keys(this.b).length})}function w(a,c){const b=a.length,e=A(c),d=[];for(let l=0,g=0;l=g&&(a=a[h-(d+.5>>0)],a=a[b]||(a[b]=[]),a[a.length]=e);return d}function F(a,c){if(a){const b=Object.keys(a);for(let e=0,d=b.length;ea?1:a?-1:0}function O(a,c,b,e,d){e=[];let l;const g=a.length;if(1b&&(e=e.slice(0,b)));return e}function C(a){return"string"===typeof a}function A(a){return"function"===typeof a}function D(a){return"undefined"===typeof a}function I(a){const c=Array(a);for(let b=0;bk;c--)f=l.substring(k,c),B(r,e,f,a,b,h,p,u-1)}break;default:if(g=B(r,e,l,a,1,h,p,u-1),q&&1=p)for(g=e._ctx[l]||(e._ctx[l]=v()),l=this.f[l]||(this.f[l]=I(u-(p||0))),h=n-q,f=n+q+1,0>h&&(h=0),f>d&&(f=d);h=d&&(this.v=this.g),this.v===this.g&& -(this.cache&&this.l.set(b,this.o),this.G&&this.G(this.o)));return this}function I(a,b){const c=a.length,d=D(b),e=[];for(let f=0,k=0;f=k&&(a=a[p-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function P(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;da?1:a?-1:0}function aa(a,b){a=a[A];b=b[A];return ab?1:0}function Z(a,b){const c=A.length;for(let d=0;db?1:0}function R(a,b,c,d){c=[];let e;const f= -a.length;if(1b&&(c=c.slice(0, -b)));return c}function C(a){return"string"===typeof a}function w(a){return a.constructor===Array}function D(a){return"function"===typeof a}function B(a){return"object"===typeof a}function v(a){return"undefined"===typeof a}function S(a){const b=Array(a);for(let c=0;c=this.m.length&&(this.D=0),this.m[this.D].postMessage({add:!0,id:a,content:b}),this.b[f]=""+this.D,c&&c(),this;if(!e){if(this.async&&"function"!==typeof importScripts){let e=this;f=new Promise(function(c){setTimeout(function(){e.add(a,b,null,d,!0);e=null;c()})});if(c)f.then(c);else return f; -return this}if(c)return this.add(a,b,null,d,!0),c(),this}b=this.encode(b);if(!b.length)return this;c=this.f;e=D(c)?c(b):b.split(U);this.filter&&(e=I(e,this.filter));const h=u();h._ctx=u();const q=e.length,n=this.threshold,z=this.depth,F=this.c,M=this.i,O=this.F;for(let b=0;bl;c--)m=k.substring(l,c),L(M,h,m,a,b,g,n,F-1)}break;default:if(p=L(M,h,k,a,1,g,n,F-1),z&&1=n)for(p=h._ctx[k]||(h._ctx[k]=u()),k=this.j[k]||(this.j[k]=S(F-(n||0))),g=b-z,m=b+z+1,0>g&&(g=0),m>q&&(m=q);gc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return a}();return h}(function(){const x={},G="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(h,y,I,K,H){I=G?URL.createObjectURL(new Blob(["("+I.toString()+")()"],{type:"text/javascript"})):h+".min.js";h+="-"+y;x[h]||(x[h]=[]);x[h][H]=new Worker(I);x[h][H].onmessage=K;return x[h][H]}}()), -this); +'use strict';(function(z,G,k){let A;(A=k.define)&&A.amd?A([],function(){return G}):(A=k.modules)?A[z.toLowerCase()]=G:"object"===typeof exports?module.exports=G:k[z]=G})("FlexSearch",function X(z){function k(a,c){const b=c?c.id:a&&a.id;this.id=b||0===b?b:Y++;this.init(a,c);H(this,"index",function(){return this.b});H(this,"length",function(){return Object.keys(this.b).length})}function A(a,c,b,d){this.v!==this.g&&(this.o=this.o.concat(b),this.v++,d&&this.o.length>=d&&(this.v=this.g),this.v===this.g&& +(this.cache&&this.l.set(c,this.o),this.G&&this.G(this.o)));return this}function I(a,c){const b=a.length,d=E(c),e=[];for(let f=0,h=0;f=h&&(a=a[m-(e+.5>>0)],a=a[b]||(a[b]=[]),a[a.length]=d);return e}function N(a,c){if(a){const b=Object.keys(a);for(let d=0,e=b.length;da?1:a?-1:0}function aa(a,c){a=a[B];c=c[B];return ac?1:0}function Z(a,c){const b=B.length;for(let d=0;dc?1:0}function P(a,c,b,d,e){d=[];let f;const h= +a.length;if(1b&&(d=d.slice(0,b)));return d}function D(a){return"string"===typeof a}function y(a){return a.constructor===Array}function E(a){return"function"===typeof a}function C(a){return"object"===typeof a}function w(a){return"undefined"===typeof a}function S(a){const c=Array(a);for(let b=0;b=this.m.length&&(this.D=0),this.m[this.D].postMessage({add:!0,id:a,content:c}),this.b[f]=""+this.D,b&&b(),this;if(!e){if(this.async&&"function"!==typeof importScripts){let e=this;f=new Promise(function(b){setTimeout(function(){e.add(a, +c,null,d,!0);e=null;b()})});if(b)f.then(b);else return f;return this}if(b)return this.add(a,c,null,d,!0),b(),this}c=this.encode(c);if(!c.length)return this;b=this.f;e=E(b)?b(c):c.split(U);this.filter&&(e=I(e,this.filter));const l=u();l._ctx=u();const p=e.length,k=this.threshold,x=this.depth,r=this.c,v=this.i,q=this.F;for(let c=0;cn;b--)g=h.substring(n,b),L(v,l,g,a,c,t,k,r-1)}break;default:if(m=L(v,l,h,a,1,t,k,r-1),x&&1=k)for(m=l._ctx[h]||(l._ctx[h]=u()),h=this.j[h]||(this.j[h]=S(r-(k||0))),t=c-x,g=c+x+1,0>t&&(t=0),g>p&&(g=p);td;c--)e=f[c-1],f[c]=e,b[e]=c;f[d]=a;b[a]=d}}}return b};return a}();return k}(function(){const z={},G="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(k,A,I,K,H){I=G?URL.createObjectURL(new Blob(["("+I.toString()+")()"], +{type:"text/javascript"})):k+".min.js";k+="-"+A;z[k]||(z[k]=[]);z[k][H]=new Worker(I);z[k][H].onmessage=K;return z[k][H]}}()),this); diff --git a/dist/flexsearch.node.js b/dist/flexsearch.node.js index 7b08a95..c151b07 100644 --- a/dist/flexsearch.node.js +++ b/dist/flexsearch.node.js @@ -1,35 +1,35 @@ /* - FlexSearch v0.5.2 + FlexSearch v0.5.3 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(h,C,D){let z;(z=D.define)&&z.amd?z([],function(){return C}):(z=D.modules)?z[h.toLowerCase()]=C:"object"===typeof exports?module.exports=C:D[h]=C})("FlexSearch",function(){function h(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:T++;this.init(a,b);z(this,"index",function(){return this.c});z(this,"length",function(){return Object.keys(this.c).length})}function C(a,b){const c=a.length,d=E(b),e=[];for(let f=0,k=0;f=k&&(a=a[p-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function L(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;da?1:a?-1:0}function V(a,b){a=a[y];b=b[y];return ab?1:0}function U(a,b){const c=y.length;for(let d=0;db?1:0}function N(a,b,c,d){c=[];let e;const f=a.length;if(1b&&(c=c.slice(0,b)));return c}function B(a){return"string"===typeof a}function v(a){return a.constructor===Array}function E(a){return"function"===typeof a}function A(a){return"object"===typeof a}function w(a){return"undefined"=== -typeof a}function O(a){const b=Array(a);for(let c=0;cl;c--)m=k.substring(l,c),H(I,r,m,a,b,g,n,h-1)}break;default:if(p=H(I,r,k,a,1,g,n,h-1),x&&1=n)for(p=r._ctx[k]||(r._ctx[k]=t()),k=this.i[k]||(this.i[k]=O(h-(n||0))),g=b-x,m=b+x+1,0>g&&(g=0),m>q&&(m=q);gc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return a}();return h}(!1),this); +'use strict';(function(k,D,E){let z;(z=E.define)&&z.amd?z([],function(){return D}):(z=E.modules)?z[k.toLowerCase()]=D:"object"===typeof exports?module.exports=D:E[k]=D})("FlexSearch",function(){function k(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:V++;this.init(a,b);z(this,"index",function(){return this.c});z(this,"length",function(){return Object.keys(this.c).length})}function D(a,b){const c=a.length,d=F(b),e=[];for(let f=0,h=0;f=h&&(a=a[n-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function M(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;da?1:a?-1:0}function X(a,b){a=a[y];b=b[y];return ab?1:0}function W(a,b){const c=y.length;for(let d=0;db?1:0}function O(a,b,c,d,e){d=[];let f;const h=a.length;if(1c&&(d=d.slice(0,c)));return d}function C(a){return"string"===typeof a}function w(a){return a.constructor===Array}function F(a){return"function"=== +typeof a}function B(a){return"object"===typeof a}function x(a){return"undefined"===typeof a}function Q(a){const b=Array(a);for(let c=0;cm;c--)p=h.substring(m,c),J(u,l,p,a,b,g,t,k-1)}break;default:if(n=J(u,l,h,a,1,g,t,k-1),A&&1=t)for(n=l._ctx[h]||(l._ctx[h]=r()),h=this.i[h]||(this.i[h]=Q(k-(t||0))),g=b-A,p=b+A+1,0>g&&(g=0),p>q&&(p=q);gc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return a}();return k}(!1),this); diff --git a/flexsearch.js b/flexsearch.js index 11059e7..b3cffb8 100644 --- a/flexsearch.js +++ b/flexsearch.js @@ -1,5 +1,5 @@ /**! - * @preserve FlexSearch v0.5.2 + * @preserve FlexSearch v0.5.3 * Copyright 2019 Nextapps GmbH * Author: Thomas Wilkerling * Released under the Apache 2.0 Licence @@ -1381,12 +1381,12 @@ return result; } - function merge_and_sort(query, result, sort, limit, where, cursor){ + function merge_and_sort(query, bool, result, sort, limit, where, cursor){ const doc = this._doc; const suggest = SUPPORT_SUGGESTIONS && this.suggest; - result = intersect(result, where ? 0 : limit, cursor, suggest); + result = intersect(result, bool, where ? 0 : limit, cursor, suggest); result = enrich_documents(result, doc); if(where){ @@ -1455,9 +1455,6 @@ let _query = query; let threshold; - //let boost; - let where; - let sort; let cursor; let result = []; @@ -1475,17 +1472,6 @@ } } - if(SUPPORT_DOCUMENTS){ - - //boost = query["boost"]; - sort = query["sort"]; - - if(SUPPORT_WHERE){ - - where = query["where"]; - } - } - //cursor = this.paging && query["cursor"]; limit = query["limit"]; threshold = query["threshold"]; @@ -1494,6 +1480,10 @@ if(SUPPORT_DOCUMENTS && this.doc){ + //let boost = query["boost"]; + let where = SUPPORT_WHERE && _query["where"]; + let bool = _query["bool"]; + let sort = _query["sort"]; const doc_idx = this.doc["index"]; let queries; @@ -1515,7 +1505,14 @@ for(let i = 0; i < _query.length; i++){ - field[i] = _query[i]["field"]; + const current = _query[i]; + + field[i] = current["field"]; + + // TODO: improve array notation (redundancy) + bool = current["bool"]; + sort = current["sort"]; + where = SUPPORT_WHERE && current["where"]; } } else{ @@ -1523,10 +1520,10 @@ field = this.doc["keys"]; } - if(sort){ - - _query["sort"] = null; - } + // if(sort){ + // + // _query["sort"] = null; + // } const len = field.length; @@ -1542,7 +1539,7 @@ if(callback){ - return callback(merge_and_sort.call(this, query, result, sort, limit, where, cursor)); + return callback(merge_and_sort.call(this, query, bool, result, sort, limit, where, cursor)); } else if(SUPPORT_ASYNC && this.async){ @@ -1552,13 +1549,13 @@ Promise.all(/** @type {!Iterable} */ (result)).then(function(values){ - resolve(merge_and_sort.call(self, query, values, sort, limit, where, cursor)); + resolve(merge_and_sort.call(self, query, bool, values, sort, limit, where, cursor)); }); }); } else{ - return merge_and_sort.call(this, query, result, sort, limit, where, cursor); + return merge_and_sort.call(this, query, bool, result, sort, limit, where, cursor); } } @@ -1588,7 +1585,7 @@ "limit": limit, "cursor": cursor, "threshold": threshold, - "where": where, + //"where": where, "content": query }); } @@ -1833,22 +1830,25 @@ found = false; } - if(found){ + if(!SUPPORT_DOCUMENTS || !this.doc){ - // Not handled by intersection: + if(found){ - result = intersect(check, limit, cursor, /*SUPPORT_DOCUMENTS && this._doc,*/ SUPPORT_SUGGESTIONS && this.suggest); + // Not handled by intersection: - // Handled by intersection: + result = intersect(check, false, limit, cursor, /*SUPPORT_DOCUMENTS && this._doc,*/ SUPPORT_SUGGESTIONS && this.suggest); - //result = intersect_3d(check, limit, this.suggest); - } + // Handled by intersection: - // store result to cache + //result = intersect_3d(check, limit, this.suggest); + } - if(SUPPORT_CACHE && this.cache && (!SUPPORT_DOCUMENTS || !this.doc)){ + // store result to cache - this._cache.set(query, result); + if(SUPPORT_CACHE && this.cache){ + + this._cache.set(query, result); + } } if(PROFILER){ @@ -3047,13 +3047,14 @@ /** * @param {!Array>} arrays + * @param {string|boolean=} bool * @param {number=} limit * @param {number=} cursor * @param {boolean=} suggest * @returns {Array} */ - function intersect(arrays, limit, cursor, /*docs,*/ suggest) { + function intersect(arrays, bool, limit, cursor, /*docs,*/ suggest) { let result = []; let suggestions; @@ -3061,36 +3062,73 @@ if(length_z > 1){ + bool = (bool === "or"); + // const bool_or = (bool === "or"); + // const bool_and = (bool === "and") || !bool; + // const bool_not = (bool === "not"); + // pre-sort arrays //TODO: test strategy //arrays.sort(sort_by_length_down); + const check = create_object(); + let arr /*= arrays[0]*/; + let z = -1; // start from 0 + let length /*= arr.length*/; + // fill initial map - const check = create_object(); - let arr = arrays[0]; - let length = arr.length; let i = 0; - - while(i < length) { - - check["@" + arr[i++]] = 1; - } + let first_result; // loop through arrays - let tmp, count = 0; - let z = 0; // start from 1 + let tmp, init = true, count = 0; while(++z < length_z){ - let found = false; const is_final_loop = (z === (length_z - 1)); - suggestions = []; arr = arrays[z]; length = arr.length; + + if(!length){ + + if(!bool && !suggest){ + + return result; + } + + if(is_final_loop && !count){ + + return first_result || result; + } + + continue; + } + + if(init){ + + if(is_final_loop){ + + return arr; + } + + while(i < length) { + + check["@" + arr[i++]] = 1; + } + + first_result = arr; + init = false; + + continue; + } + + let found = false; + + suggestions = []; i = 0; while(i < length){ @@ -3103,7 +3141,7 @@ const check_val = check[index]; - if(check_val === z){ + if(bool || (check_val === z) /*|| (bool_not && !check_val)*/){ // fill in during last round @@ -3681,8 +3719,6 @@ )), this); - /* istanbul ignore next */ - /** -------------------------------------------------------------------------------------- * UMD Wrapper for Browser and Node.js * @param {!string} name @@ -3694,6 +3730,8 @@ function provide(name, factory, root){ + /* istanbul ignore next */ + let prop; // AMD (RequireJS) diff --git a/package.json b/package.json index 35b93ba..b032ed7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flexsearch", - "version": "0.5.2", + "version": "0.5.3", "description": "Next-Generation full text search library with zero dependencies.", "homepage": "https://github.com/nextapps-de/flexsearch/", "author": "Thomas Wilkerling", diff --git a/test/test.es6.js b/test/test.es6.js index fb73c3d..ccb0fa9 100644 --- a/test/test.es6.js +++ b/test/test.es6.js @@ -80,25 +80,25 @@ describe("Index Multi-Field Documents (ES6)", function(){ expect(await index.search({field: "data:body", query: "title"})).to.have.lengthOf(0); expect(await index.search({field: "data:title", query: "body"})).to.have.lengthOf(0); - //TODO: provide logical operator "OR" - // expect(await index.search({field: ["data:title", "data:body"], query: "body"})).to.have.members(data); - // expect(await index.search({field: ["data:body", "data:title"], query: "title"})).to.have.members(data); + expect(await index.search({field: ["data:title", "data:body"], query: "body", bool: "or"})).to.have.members(data); + expect(await index.search({field: ["data:body", "data:title"], query: "title", bool: "or"})).to.have.members(data); + expect(await index.search({field: ["data:body"], query: "body"})).to.have.members(data); expect(await index.search({field: "data:title", query: "title"})).to.have.members(data); - //TODO: provide logical operator "OR" - // expect(await index.search({query: "body"})).to.have.members(data); - // expect(await index.search("title")).to.have.members(data); + expect(await index.search({query: "body", bool: "or"})).to.have.members(data); + expect(await index.search("title", {bool: "or"})).to.have.members(data); + expect(await index.search({field: ["data:body"], query: "body"})).to.have.members(data); expect(await index.search({field: "data:title", query: "title"})).to.have.members(data); await index.update(update); - //TODO: provide logical operator "OR" - // expect(await index.search("foo")).not.to.have.members(data); - // expect(await index.search("bar")).not.to.have.members(data); - // expect(await index.search("foo")).to.have.members(update); - // expect(await index.search("bar")).to.have.members(update); + expect(await index.search("foo", {bool: "or"})).not.to.have.members(data); + expect(await index.search("bar", {bool: "or"})).not.to.have.members(data); + expect(await index.search("foo", {bool: "or"})).to.have.members(update); + expect(await index.search("bar", {bool: "or"})).to.have.members(update); + expect(await index.search("foo", {field: "data:title"})).not.to.have.members(data); expect(await index.search("bar", {field: "data:body"})).not.to.have.members(data); expect(await index.search("foo", {field: "data:title"})).to.have.members(update); @@ -137,25 +137,25 @@ describe("Index Multi-Field Documents (ES6)", function(){ expect(await index.search({field: "data:body", query: "title"})).to.have.lengthOf(0); expect(await index.search({field: "data:title", query: "body"})).to.have.lengthOf(0); - //TODO: provide logical operator "OR" - // expect(await index.search({field: ["data:title", "data:body"], query: "body"})).to.have.members(data); - // expect(await index.search({field: ["data:body", "data:title"], query: "title"})).to.have.members(data); + expect(await index.search({field: ["data:title", "data:body"], query: "body", bool: "or"})).to.have.members(data); + expect(await index.search({field: ["data:body", "data:title"], query: "title", bool: "or"})).to.have.members(data); + expect(await index.search({field: ["data:body"], query: "body"})).to.have.members(data); expect(await index.search({field: "data:title", query: "title"})).to.have.members(data); - //TODO: provide logical operator "OR" - // expect(await index.search({query: "body"})).to.have.members(data); - // expect(await index.search("title")).to.have.members(data); + expect(await index.search({query: "body", bool: "or"})).to.have.members(data); + expect(await index.search("title", {bool: "or"})).to.have.members(data); + expect(await index.search({query: "body", field: "data:body"})).to.have.members(data); expect(await index.search("title", {field: "data:title"})).to.have.members(data); await index.update(update); - //TODO: provide logical operator "OR" - // expect(await index.search("foo")).not.to.have.members(data); - // expect(await index.search("bar")).not.to.have.members(data); - // expect(await index.search("foo")).to.have.members(update); - // expect(await index.search("bar")).to.have.members(update); + expect(await index.search("foo", {bool: "or"})).not.to.have.members(data); + expect(await index.search("bar", {bool: "or"})).not.to.have.members(data); + expect(await index.search("foo", {bool: "or"})).to.have.members(update); + expect(await index.search("bar", {bool: "or"})).to.have.members(update); + expect(await index.search("foo", {field: "data:title"})).not.to.have.members(data); expect(await index.search("bar", {field: "data:body"})).not.to.have.members(data); expect(await index.search("foo", {field: "data:title"})).to.have.members(update); diff --git a/test/test.js b/test/test.js index 3c3026a..2b4d31b 100644 --- a/test/test.js +++ b/test/test.js @@ -132,9 +132,12 @@ describe("Initialize", function(){ cache: true }); - expect(flexsearch_default).to.be.an.instanceOf(FlexSearch); - expect(flexsearch_sync).to.be.an.instanceOf(FlexSearch); - expect(flexsearch_async).to.be.an.instanceOf(FlexSearch); + it("Should have correct constructors", function(){ + + expect(flexsearch_default).to.be.an.instanceOf(FlexSearch); + expect(flexsearch_sync).to.be.an.instanceOf(FlexSearch); + expect(flexsearch_async).to.be.an.instanceOf(FlexSearch); + }); it("Should have correct uuids", function(){ @@ -156,6 +159,16 @@ describe("Initialize", function(){ expect(flexsearch_default).to.respondTo("remove"); expect(flexsearch_default).to.respondTo("clear"); expect(flexsearch_default).to.respondTo("init"); + expect(flexsearch_default).to.respondTo("destroy"); + + expect(flexsearch_default).to.hasOwnProperty("length"); + expect(flexsearch_default).to.hasOwnProperty("index"); + + if(env !== "light"){ + + expect(flexsearch_default).to.respondTo("where"); + expect(flexsearch_default).to.respondTo("find"); + } if(env !== "light" && env !== "min"){ @@ -1327,18 +1340,22 @@ if(env !== "light") describe("Index Multi-Field Documents", function(){ expect(index.search({field: "data:body", query: "title"})).to.have.lengthOf(0); expect(index.search({field: "data:title", query: "body"})).to.have.lengthOf(0); - //TODO: provide logical operator "OR" - //expect(index.search({field: ["data:title", "data:body"], query: "body"})).to.have.members(data); - //expect(index.search({field: ["data:body", "data:title"], query: "title"})).to.have.members(data); expect(index.search({field: "data:body", query: "body"})).to.have.members(data); expect(index.search({field: ["data:title"], query: "title"})).to.have.members(data); - //TODO: provide logical operator "OR" - //expect(index.search({query: "body"})).to.have.members(data); - //expect(index.search("title")).to.have.members(data); + expect(index.search({field: ["data:title", "data:body"], query: "body"})).to.have.lengthOf(0); + expect(index.search({field: ["data:body", "data:title"], query: "title"})).to.have.lengthOf(0); + expect(index.search({field: ["data:title", "data:body"], query: "body", bool: "and"})).to.have.lengthOf(0); + expect(index.search({field: ["data:body", "data:title"], query: "title", bool: "and"})).to.have.lengthOf(0); + expect(index.search({field: ["data:title", "data:body"], query: "body", bool: "or"})).to.have.members(data); + expect(index.search({field: ["data:body", "data:title"], query: "title", bool: "or"})).to.have.members(data); + expect(index.search("body", {field: "data:body"})).to.have.members(data); expect(index.search("title", {field: ["data:title"]})).to.have.members(data); + expect(index.search({query: "body", bool: "or"})).to.have.members(data); + //expect(index.search("title", {bool: "or"})).to.have.members(data); + expect(index.search({ field: "data:title", @@ -1347,51 +1364,47 @@ if(env !== "light") describe("Index Multi-Field Documents", function(){ })).to.have.members(data); - //TODO: provide logical operator "OR" - // expect(index.search([{ - // - // field: "data:title", - // query: "body", - // boost: 2 - // },{ - // field: "data:body", - // query: "body", - // boost: 2 - // - // }])).to.have.members(data); + expect(index.search([{ + + field: "data:title", + query: "body", + bool: "or" + },{ + field: "data:body", + query: "body", + bool: "or" + + }])).to.have.members(data); expect(index.search("title", { - field: "data:title", - boost: 2 + field: "data:title" })).to.have.members(data); expect(index.search("title", { - field: "data:body", - boost: 2 + field: "data:body" })).to.have.lengthOf(0); - //TODO: provide logical operator "OR" - // expect(index.search("body", [{ - // - // field: "data:title", - // boost: 2 - // },{ - // field: "data:body", - // boost: 2 - // - // }])).to.have.members(data); + expect(index.search("body", [{ + + field: "data:title", + bool: "or" + },{ + field: "data:body", + bool: "or" + + }])).to.have.members(data); index.update(update); - //TODO: provide logical operator "OR" - // expect(index.search("foo")).not.to.have.members(data); - // expect(index.search("bar")).not.to.have.members(data); - // expect(index.search("foo")).to.have.members(update); - // expect(index.search("bar")).to.have.members(update); + expect(index.search("foo", {bool: "or"})).not.to.have.members(data); + expect(index.search("bar", {bool: "or"})).not.to.have.members(data); + expect(index.search("foo", {bool: "or"})).to.have.members(update); + expect(index.search("bar", {bool: "or"})).to.have.members(update); + expect(index.search("foo", {field: "data:title"})).not.to.have.members(data); expect(index.search("bar", {field: "data:body"})).not.to.have.members(data); expect(index.search("foo", {field: "data:title"})).to.have.members(update); @@ -1440,15 +1453,15 @@ if(env !== "light") describe("Index Multi-Field Documents", function(){ expect(index.search({field: "data:body", query: "title"})).to.have.lengthOf(0); expect(index.search({field: "data:title", query: "body"})).to.have.lengthOf(0); - //TODO: provide logical operator "OR" - //expect(index.search({field: ["data:title", "data:body"], query: "body"})).to.have.members(data); - //expect(index.search({field: ["data:body", "data:title"], query: "tle"})).to.have.members(data); - expect(index.search({field: ["data:body"], query: "body"})).to.have.members(data); - expect(index.search({field: "data:title", query: "tle"})).to.have.members(data); + expect(index.search({field: ["data:title", "data:body"], query: "body", bool: "or"})).to.have.members(data); + expect(index.search({field: ["data:body", "data:title"], query: "tle", bool: "or"})).to.have.members(data); + + expect(index.search({field: ["data:body"], query: "body", bool: "or"})).to.have.members(data); + expect(index.search({field: "data:title", query: "tle", bool: "or"})).to.have.members(data); + + expect(index.search({query: "body", bool: "or"})).to.have.members(data); + expect(index.search("tle", {bool: "or"})).to.have.members(data); - //TODO: provide logical operator "OR" - //expect(index.search({query: "body"})).to.have.members(data); - //expect(index.search("tle")).to.have.members(data); expect(index.search({query: "body", field: "data:body"})).to.have.members(data); expect(index.search("tle", {field: "data:title"})).to.have.members(data); @@ -1459,16 +1472,17 @@ if(env !== "light") describe("Index Multi-Field Documents", function(){ })).to.have.members(data); - //TODO: provide logical operator "OR" - // expect(index.search([{ - // - // field: "data:title", - // query: "body" - // },{ - // field: "data:body", - // query: "body" - // - // }])).to.have.members(data); + expect(index.search([{ + + field: "data:title", + query: "body", + bool: "or" + },{ + field: "data:body", + query: "body", + bool: "or" + + }])).to.have.members(data); expect(index.search("tle", { @@ -1482,22 +1496,23 @@ if(env !== "light") describe("Index Multi-Field Documents", function(){ })).to.have.lengthOf(0); - //TODO: provide logical operator "OR" - // expect(index.search("body", [{ - // - // field: "data:title" - // },{ - // field: "data:body" - // - // }])).to.have.members(data); + expect(index.search("body", [{ + + field: "data:title", + bool: "or" + },{ + field: "data:body", + bool: "or" + + }])).to.have.members(data); index.update(update); - //TODO: provide logical operator "OR" - // expect(index.search("foo")).not.to.have.members(data); - // expect(index.search("bar")).not.to.have.members(data); - // expect(index.search("foo")).to.have.members(update); - // expect(index.search("bar")).to.have.members(update); + expect(index.search("foo", {bool: "or"})).not.to.have.members(data); + expect(index.search("bar", {bool: "or"})).not.to.have.members(data); + expect(index.search("foo", {bool: "or"})).to.have.members(update); + expect(index.search("bar", {bool: "or"})).to.have.members(update); + expect(index.search("foo", {field: "data:title"})).not.to.have.members(data); expect(index.search("bar", {field: "data:body"})).not.to.have.members(data); expect(index.search("foo", {field: "data:title"})).to.have.members(update); @@ -1803,6 +1818,23 @@ if(env !== "light") describe("Export / Import", function(){ }); }); +// ------------------------------------------------------------------------ +// Presets +// ------------------------------------------------------------------------ + +describe("Presets", function(){ + + it("Should have been properly initialized", function(){ + + expect(FlexSearch.create("memory").length).to.equal(0); + expect(FlexSearch.create("speed").length).to.equal(0); + expect(FlexSearch.create("match").length).to.equal(0); + expect(FlexSearch.create("score").length).to.equal(0); + expect(FlexSearch.create("balance").length).to.equal(0); + expect(FlexSearch.create("fast").length).to.equal(0); + }); +}); + // ------------------------------------------------------------------------ // Feature Tests // ------------------------------------------------------------------------ @@ -1912,6 +1944,28 @@ if(env !== "light" && env !== "min"){ }); } +// ------------------------------------------------------------------------ +// Destroy +// ------------------------------------------------------------------------ + +describe("Destroy", function(){ + + it("Should have been destroyed properly", function(){ + + var index = FlexSearch.create() + .add(0, "foo") + .add(1, "bar"); + + expect(index.search("foo")).to.include(0); + expect(index.search("bar")).to.include(1); + + index.destroy(); + + expect(index.search("foo")).to.have.lengthOf(0); + expect(index.search("bar")).to.have.lengthOf(0); + }); +}); + // ------------------------------------------------------------------------ // Chaining // ------------------------------------------------------------------------