diff --git a/README.md b/README.md index 1fbef05..07df007 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ Comparison: *** +
/\W+/
).f;d--)k=g[d-1],g[d]=k,e[k]=d;g[f]=a;e[a]=f}}}return b};return a}();return g}(function(){var d={},m="undefined"!==typeof Blob&& +"undefined"!==typeof URL&&URL.createObjectURL;return function(g,k,p,Q,f){p=m?URL.createObjectURL(new Blob(["("+p.toString()+")()"],{type:"text/javascript"})):g+".es5.js";g+="-"+k;d[g]||(d[g]=[]);d[g][f]=new Worker(p);d[g][f].onmessage=Q;console.log("Register Worker: "+g+"@"+f);return d[g][f]}}()),this); diff --git a/dist/flexsearch.light.js b/dist/flexsearch.light.js index 3cf78e8..4c9c1f7 100644 --- a/dist/flexsearch.light.js +++ b/dist/flexsearch.light.js @@ -1,19 +1,19 @@ /* - FlexSearch v0.6.0 + FlexSearch v0.6.1 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(e,z,t){let k;(k=t.define)&&k.amd?k([],function(){return z}):(k=t.modules)?k[e.toLowerCase()]=z:"object"===typeof exports?module.exports=z:t[e]=z})("FlexSearch",function(){function e(a,c){const b=c?c.id:a&&a.id;this.id=b||0===b?b:L++;this.init(a,c);t(this,"index",function(){return Object.keys(this.b)});t(this,"length",function(){return this.index.length})}function z(a,c){const b=a.length,f=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]=f);return d}function E(a,c){if(a){const b=Object.keys(a);for(let f=0,d=b.length;fa?1:a?-1:0}function F(a,c,b){return a?{page:a,next:c?""+c:null,result:b}:b}function C(a){return"string"===typeof a}function A(a){return"function"===typeof a}function D(a){return"undefined"===typeof a}function H(a){const c=Array(a);for(let b=0;bm;c--)n=l.substring(m,c),B(r,f,n,a,b,h,q,p-1)}break;default:if(g=B(r,f,l,a,1,h,q,p-1),k&&1 =q)for(g=f._ctx[l]||(f._ctx[l]=y()),l=this.f[l]||(this.f[l]=H(p-(q||0))),h=e-k,n=e+k+1,0>h&&(h=0),n>d&&(n=d);h a?1:a?-1:0}function F(a,c,b){return a?{page:a,next:c?""+c:null,result:b}:b}function C(a){return"string"===typeof a}function A(a){return"function"===typeof a}function D(a){return"undefined"===typeof a}function H(a){const c=Array(a);for(let b=0;bm;c--)n=l.substring(m,c),B(q,f,n,a,b,h,r,p-1)}break;default:if(g=B(q,f,l,a,1,h,r,p-1),k&&1 =r)for(g=f._ctx[l]||(f._ctx[l]=y()),l=this.f[l]||(this.f[l]=H(p-(r||0))),h=e-k,n=e+k+1,0>h&&(h=0),n>d&&(n=d);h =d&&(this.u=this.g),this.u===this.g&&(this.cache&&this.l.set(b,this.o),this.F&&this.F(this.o)));return this}function O(a,b){const c=a.length,d=J(b),e=[];for(let f=0,g=0;f =g&&(a=a[m-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function T(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;d a?1:a?-1:0}function fa(a,b){a=a[F];b=b[F];return ab?1:0}function ea(a, -b){const c=F.length;for(let d=0;d b?1:0}function K(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c}function V(a,b,c,d,e,f,g){let m;f=[];let n;const r=a.length;!0===c?(c="0",n=""):n=c&&c.split(":");if(1 =this.m.length&&(this.C=0),this.m[this.C].postMessage({add:!0,id:a,content:b}),this.c[f]=""+this.C,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=J(c)?c(b):b.split(Z);this.filter&&(e=O(e,this.filter));const l=q();l._ctx= -q();const p=e.length,r=this.threshold,u=this.depth,y=this.b,z=this.j,v=this.D;for(let b=0;b k;c--)h=g.substring(k,c),R(z,l,h,a,b,n,r,y-1)}break;default:if(m=R(z,l,g,a,1,n,r,y-1),u&&1
=r)for(m=l._ctx[g]|| -(l._ctx[g]=q()),g=this.i[g]||(this.i[g]=X(y-(r||0))),n=b-u,h=b+u+1,0>n&&(n=0),h>p&&(h=p);n
c;d--)e=f[d-1],f[d]=e,a[e]=d;f[c]=b;a[b]=c}}}return a};return a}();return l}(function(){const t= -{},M="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(l,E,O,Q,N){O=M?URL.createObjectURL(new Blob(["("+O.toString()+")()"],{type:"text/javascript"})):l+".min.js";l+="-"+E;t[l]||(t[l]=[]);t[l][N]=new Worker(O);t[l][N].onmessage=Q;return t[l][N]}}()),this); +'use strict';(function(x,N,l){let z;(z=l.define)&&z.amd?z([],function(){return N}):(z=l.modules)?z[x.toLowerCase()]=N:"object"===typeof exports?module.exports=N:l[x]=N})("FlexSearch",function da(x){function l(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:ea++;this.init(a,b);O(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].c):Object.keys(this.c)});O(this,"length",function(){return this.index.length})}function z(a,b,c,d){this.u!==this.g&&(this.o=this.o.concat(c),this.u++, +d&&this.o.length>=d&&(this.u=this.g),this.u===this.g&&(this.cache&&this.l.set(b,this.o),this.F&&this.F(this.o)));return this}function P(a,b){const c=a.length,d=J(b),e=[];for(let g=0,f=0;g =f&&(a=a[r-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function W(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;d a?1:a?-1:0}function ha(a,b){a=a[E];b=b[E];return ab?1:0}function fa(a, +b){const c=E.length;for(let d=0;d b?1:0}function L(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c}function Y(a,b,c,d,e,g,f){let r,q=[],n;const p=a.length;!0===c?(c="0",n=""):n=c&&c.split(":");if(1 =this.m.length&&(this.C=0),this.m[this.C].postMessage({add:!0,id:a,content:b}),this.c[g]=""+this.C,c&&c(),this;if(!e){if(this.async&&"function"!==typeof importScripts){let e=this;g=new Promise(function(c){setTimeout(function(){e.add(a,b,null,d,!0);e=null;c()})});if(c)g.then(c);else return g;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=J(c)?c(b):b.split(this.split);this.filter&&(e=P(e,this.filter));const m=u();m._ctx=u();const k=e.length,h=this.threshold,l=this.depth,v=this.b,A=this.j,Q=this.D;for(let b=0;b
p;c--)n=f.substring(p,c),T(A,m,n,a,b,q,h,v-1)}break;default:if(r=T(A,m,f,a,1,q,h,v-1),l&&1 =h)for(r=m._ctx[f]||(m._ctx[f]=u()),f=this.i[f]||(this.i[f]=Z(v-(h||0))),q=b-l,n=b+l+1,0>q&&(q=0),n>k&&(n=k);q d;b--)e=f[b-1],f[b]=e,c[e]=b;f[d]=a;c[a]=d}}}return c};return a}();return l}(function(){const x={},N="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(l,z,P,S,O){P=N?URL.createObjectURL(new Blob(["("+P.toString()+")()"],{type:"text/javascript"})):l+".min.js";l+="-"+z;x[l]||(x[l]=[]);x[l][O]=new Worker(P);x[l][O].onmessage=S;return x[l][O]}}()),this); diff --git a/dist/flexsearch.node.js b/dist/flexsearch.node.js index 1024d37..024cd99 100644 --- a/dist/flexsearch.node.js +++ b/dist/flexsearch.node.js @@ -1,36 +1,36 @@ /* - FlexSearch v0.6.0 + FlexSearch v0.6.1 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(l,I,J){let G;(G=J.define)&&G.amd?G([],function(){return I}):(G=J.modules)?G[l.toLowerCase()]=I:"object"===typeof exports?module.exports=I:J[l]=I})("FlexSearch",function(){function l(b,a){const c=a?a.id:b&&b.id;this.id=c||0===c?c:Z++;this.init(b,a);G(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].f):Object.keys(this.f)});G(this,"length",function(){return this.index.length})}function I(b,a){const c=b.length,d=H(a),e=[];for(let f=0,g=0;f =g&&(b=b[m-(e+.5>>0)],b=b[c]||(b[c]=[]),b[b.length]=d);return e}function P(b,a){if(b){const c=Object.keys(b);for(let d=0,e=c.length;d b?1:b?-1:0}function ba(b,a){b=b[v];a=a[v];return ba?1:0}function aa(b,a){const c=v.length;for(let d=0;d a?1:0}function K(b,a,c){return b?{page:b,next:a?""+a:null,result:c}:c}function R(b,a,c,d,e,f,g){let m;f=[];let n;const q=b.length; -!0===c?(c="0",n=""):n=c&&c.split(":");if(1 -k;c--)h=g.substring(k,c),N(z,t,h,b,a,n,q,l-1)}break;default:if(m=N(z,t,g,b,1,n,q,l-1),u&&1=q)for(m=t._ctx[g]||(t._ctx[g]=r()),g=this.h[g]||(this.h[g]=U(l-(q||0))),n=a-u,h=a+u+1,0>n&&(n=0),h>p&&(h=p);n
c;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return b}();return l}(!1),this); +'use strict';(function(m,K,L){let H;(H=L.define)&&H.amd?H([],function(){return K}):(H=L.modules)?H[m.toLowerCase()]=K:"object"===typeof exports?module.exports=K:L[m]=K})("FlexSearch",function(){function m(b,a){const c=a?a.id:b&&b.id;this.id=c||0===c?c:aa++;this.init(b,a);H(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].f):Object.keys(this.f)});H(this,"length",function(){return this.index.length})}function K(b,a){const c=b.length,d=I(a),e=[];for(let g=0,f=0;g =f&&(b=b[r-(e+.5>>0)],b=b[c]||(b[c]=[]),b[b.length]=d);return e}function T(b,a){if(b){const c=Object.keys(b);for(let d=0,e=c.length;d b?1:b?-1:0}function ca(b,a){b=b[x];a=a[x];return ba?1:0}function ba(b,a){const c=x.length;for(let d=0;d a?1:0}function M(b,a,c){return b?{page:b,next:a?""+a:null,result:c}:c}function V(b,a,c,d,e,g,f){let r,q=[],l;const n=b.length; +!0===c?(c="0",l=""):l=c&&c.split(":");if(1 n;c--)l=f.substring(n,c),Q(A,k,l,b,a,q,h,m-1)}break;default:if(r=Q(A,k,f,b,1,q,h,m-1),t&&1 =h)for(r=k._ctx[f]||(k._ctx[f]=v()),f=this.h[f]||(this.h[f]=W(m-(h||0))),q=a-t,l=a+t+1,0>q&&(q=0),l>p&&(l=p);q
c;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return b}();return m}(!1),this); diff --git a/flexsearch.js b/flexsearch.js index 98d8062..bca7279 100644 --- a/flexsearch.js +++ b/flexsearch.js @@ -1,5 +1,5 @@ /**! - * @preserve FlexSearch v0.6.0 + * @preserve FlexSearch v0.6.1 * Copyright 2019 Nextapps GmbH * Author: Thomas Wilkerling * Released under the Apache 2.0 Licence @@ -32,13 +32,14 @@ /** * @const - * @enum {boolean|string|number} + * @enum {boolean|string|number|RegExp} */ const defaults = { encode: "icase", tokenize: "forward", + split: /\W+/, // enrich: true, // clone: false, // suggest: false, @@ -127,18 +128,11 @@ let id_counter = 0; - /** - * NOTE: This could make issues on some languages (chinese, korean, thai) - * TODO: extract all language-specific stuff from the core - * @const {RegExp} - */ - - const regex_split = /\W+/; //regex("\\W+"); // regex("[\\s/-_]"); const filter = {}; const stemmer = {}; /** - * NOTE: Actually not really required when using bare objects: Object.create(null) + * NOTE: Actually not really required when using bare objects via: Object.create(null) * @const {Object } */ @@ -414,6 +408,14 @@ defaults.tokenize ); + /** @private */ + this.split = ( + + options["split"] || + this.split || + defaults.split + ); + /** @private */ this.rtl = ( @@ -924,7 +926,7 @@ //(ngram(/** @type {!string} */(content))) //: /** @type {string} */ - (content).split(regex_split) + (content).split(this.split) ) ); @@ -1185,6 +1187,8 @@ tag[tag.length] = doc; // tag[tag.length] = id; } + this._doc[id] = doc; + for(let i = 0, len = tree.length; i < len; i++){ const branch = tree[i]; @@ -1195,8 +1199,6 @@ content = (content || doc)[branch[x]]; } - this._doc[id] = doc; - const self = index[keys[i]]; let fn; @@ -1763,7 +1765,7 @@ //(ngram(_query)) //: /** @type {string} */ - (_query).split(regex_split) + (_query).split(this.split) ) ); @@ -3220,9 +3222,7 @@ while(++z < length_z){ - const current_bool = bool[z]; - - if(current_bool === "not"){ + if(bool[z] === "not"){ arr = arrays[z]; length = arr.length; @@ -3245,7 +3245,7 @@ // there was no field with "and" / "or" // TODO: this could also checked before intersection - if(!last_index){ + if(is_undefined(last_index)){ return create_page(cursor, page, result); } @@ -3258,6 +3258,9 @@ } } + let bool_and; + let bool_or; + // loop through arrays while(++z < length_z){ @@ -3267,23 +3270,21 @@ z === (last_index || length_z) - 1 ); - let bool_current; - let bool_and; - let bool_or; - if(SUPPORT_DOCUMENT && SUPPORT_OPERATOR){ if(!bool_main || !z){ - bool_current = bool_main || (bool && bool[z]); + const bool_current = bool_main || (bool && bool[z]); if(!bool_current || (bool_current === "and")){ - bool_and = true; + bool_and = has_and = true; + bool_or = false; } else if(bool_current === "or"){ bool_or = true; + bool_and = false; } else{ @@ -3295,7 +3296,7 @@ } else{ - bool_and = true; + bool_and = has_and = true; } arr = arrays[z]; @@ -3327,7 +3328,20 @@ while(i < result_length){ - check["@" + first_result[i++]] = 1; + const id = first_result[i++]; + const index = "@" + id; + + // there is no and, add items + + if(!has_not || !check_not[index]){ + + check[index] = 1; + + if(!has_and){ + + result[count++] = id; + } + } } first_result = null; @@ -3353,7 +3367,7 @@ tmp = arr[i++]; const index = "@" + tmp; - const check_val = bool_or ? z : check[index]; + const check_val = has_and ? check[index] : z; if(check_val){ @@ -3362,6 +3376,11 @@ continue; } + if(!has_and && check[index]){ + + continue; + } + if(check_val === z){ // fill in during last round @@ -3370,7 +3389,7 @@ // sadly the pointer could just applied here at the earliest // that's why pagination cannot reduce complexity actually - // should only happened when at least one "and" bool was set + // should only happened when at least one bool "and" was set // TODO: check bool and provide complexity reduction if(!pointer || (--pointer < count)){ diff --git a/package.json b/package.json index 58fd7e2..46cfaa8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flexsearch", - "version": "0.6.0", + "version": "0.6.1", "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.js b/test/test.js index f18dccb..72cda27 100644 --- a/test/test.js +++ b/test/test.js @@ -1906,6 +1906,24 @@ if(env !== "light") describe("Pagination", function(){ }); }); +describe("Custom Split", function(){ + + it("Should have been split properly", function(){ + + var index = FlexSearch.create({ + encode: false, + split: /\s+/, + tokenize: "reverse" + }); + + index.add(0, "Фообар"); + + expect(index.search("Фообар")).to.include(0); + expect(index.search("бар")).to.include(0); + expect(index.search("Фоо")).to.include(0); + }); +}); + describe("Github Issues", function(){ if(env !== "light") it("#48", function(){ @@ -1941,6 +1959,30 @@ describe("Github Issues", function(){ expect(fs.search("howdy", { bool: "or" })).to.have.members([doc[1]]); expect(fs.search("howdy -", { bool: "or" })).to.have.members([doc[1]]); }); + + if(env !== "light") it("#54", function(){ + + var docs = [{ + id: 1, + title: "Roaming Inquiry", + content: "Some content" + }, { + id: 2, + title: "New Service", + content: "This is not roaming-inquiry" + }]; + + var index = new FlexSearch({ + doc: { + id: "id", + field: ["title", "content"] + } + }); + + index.add(docs); + + expect(index.search("roaming")).to.have.members([docs[0], docs[1]]); + }); }); if(env !== "light") describe("Operators", function(){ @@ -1985,7 +2027,7 @@ if(env !== "light") describe("Operators", function(){ field: "blacklist", query: "xxx", bool: "not" - }])).to.have.length(3); + }])).to.have.members(data); expect(index.search([{ field: "title", @@ -2013,7 +2055,7 @@ if(env !== "light") describe("Operators", function(){ field: "blacklist", query: "xxx", bool: "not" - }])).to.have.length(3); + }])).to.have.members(data); expect(index.search([{ field: "title", @@ -2023,7 +2065,7 @@ if(env !== "light") describe("Operators", function(){ field: "body", query: "title", bool: "or" - }])).to.have.length(3); + }])).to.have.members(data); expect(index.search([{ field: "title", @@ -2037,7 +2079,7 @@ if(env !== "light") describe("Operators", function(){ field: "blacklist", query: "x1", bool: "not" - }])).to.have.length(2); + }])).to.have.members([data[1], data[2]]); expect(index.search([{ field: "title", @@ -2065,7 +2107,7 @@ if(env !== "light") describe("Operators", function(){ field: "body", query: "body", bool: "or" - }])).to.have.length(2); + }])).to.have.members([data[1], data[2]]); expect(index.search([{ field: "title", @@ -2079,7 +2121,7 @@ if(env !== "light") describe("Operators", function(){ field: "blacklist", query: "x2", bool: "not" - }])).to.have.length(2); + }])).to.have.members([data[0], data[2]]); expect(index.search([{ field: "blacklist", @@ -2093,7 +2135,7 @@ if(env !== "light") describe("Operators", function(){ field: "body", query: "body", bool: "and" - }])).to.have.length(2); + }])).to.have.members([data[0], data[2]]); expect(index.search([{ field: "title", @@ -2107,7 +2149,7 @@ if(env !== "light") describe("Operators", function(){ field: "body", query: "body", bool: "and" - }])).to.have.length(2); + }])).to.have.members([data[0], data[2]]); expect(index.search([{ field: "title",