From d1491da25909fcfd81b315beee9e4d78fbb7b8ed Mon Sep 17 00:00:00 2001 From: Thomas Wilkerling Date: Wed, 2 Jun 2021 10:57:18 +0200 Subject: [PATCH] improved intersection strategy --- dist/flexsearch.bundle.js | 57 ++- dist/flexsearch.compact.js | 44 +-- dist/flexsearch.debug.js | 691 +++++++++++++++++++------------------ dist/flexsearch.es5.js | 77 ++--- dist/flexsearch.light.js | 24 +- doc/0.7.0.md | 93 ++--- doc/contextual-index.svg | 2 +- src/async.js | 2 +- src/document.js | 51 +-- src/index.js | 143 ++++---- src/intersect.js | 347 ++++++++++++++----- src/worker/index.js | 2 +- 12 files changed, 825 insertions(+), 708 deletions(-) diff --git a/dist/flexsearch.bundle.js b/dist/flexsearch.bundle.js index eacbdb5..2e0c9b2 100644 --- a/dist/flexsearch.bundle.js +++ b/dist/flexsearch.bundle.js @@ -5,32 +5,31 @@ * Licence: Apache-2.0 * https://github.com/nextapps-de/flexsearch */ -(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f;var r;function t(a,b){return"undefined"!==typeof a?a:b}function w(a){const b=Array(a);for(let c=0;c=b)return f.concat(l.slice(c,b-h+c));f=f.concat(c? -l.slice(c):l);h+=p;c=0}return f}function ma(a,b){const c=x(),d=x(),e=[];for(let f=0;f=e&&(f=e-1);this.C=e;this.threshold=f;this.D=b=c&&c.I||a.tokenize||"strict";this.depth="strict"===b&&h.depth;this.G=t(h.bidirectional,!0);this.A=g="memory"=== -a.optimize;this.o=t(a.fastupdate,!0);this.B=a.minlength||1;this.map=g?w(e-f):x();e=h.resolution||e;f=h.threshold||f;f>=e&&(f=e-1);this.l=e;this.s=f;this.h=g?w(e-f):x();this.F=c&&c.F||a.rtl;this.L=(b=a.matcher||d&&d.L)&&ca(b,!1);this.M=(b=a.stemmer||d&&d.M)&&ca(b,!0);if(c=b=a.filter||d&&d.filter){c=b;d=x();for(let k=0,l=c.length;k=this.B&&(p||!q[n])){var f=Math.min(this.C/d*m|0,m);if(fh;l--)g=n.substring(h,l),g.length>=this.B&&L(this,q,g,k,a,c)}break}case "reverse":if(2< -e){for(h=e-1;0=this.B&&L(this,q,g,f,a,c);g=""}case "forward":if(1=this.B&&L(this,q,g,f,a,c);break;default:if(L(this,q,n,f,a,c),p&&1=this.B&&!f[n]){if(f[n]=1,l=Math.min((this.l-h)/d*m+k|0,m+(k-1)),lg;L(this,v,y?g:n,l,a,c,y?n:g)}}else h=Math.min(h+1,d-m)}}}}this.o||(this.register[a]=1)}return this}; -function L(a,b,c,d,e,f,g){let h=g?a.h:a.map;if(!b[c]||g&&!b[c][g])a.A&&(h=h[d]),g?(b=b[c]||(b[c]=x()),b[g]=1,h=h[g]||(h[g]=x())):b[c]=1,h=h[c]||(h[c]=[]),a.A||(h=h[d]||(h[d]=[])),f&&-1!==h.indexOf(e)||(h[h.length]=e,a.o&&(a=a.register[e]||(a.register[e]=[]),a[a.length]=h))} -r.search=function(a,b,c){B(a)?(c=a,a=c.query):B(b)&&(c=b);let d=[],e;var f=this.threshold;let g,h=0;if(c){b=c.limit;h=c.offset||0;f=t(c.threshold,f);var k=c.context;g=c.suggest}if(a&&(a=this.encode(a),e=a.length,1=this.B&&!c[v])if(this.A||g||this.map[v])l[q++]=v,c[v]=1;else return d;a=l;e=a.length}if(!e)return d;b||(b=100);c=this.C-f;f=this.l-f;k=this.depth&&1=e)));q++);if(u){if(g)return ta(l,e,0);b[b.length]=l;return}}return!c&&l}function ta(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} -function ua(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}r.contain=function(a){return!!this.register[a]};r.update=function(a,b){return this.remove(a).add(a,b)}; -r.remove=function(a,b){const c=this.register[a];if(c){if(this.o)for(let d=0,e;db||c)e=e.slice(c,c+b);d&&(e=za.call(this,e));return{tag:a,result:e}}}function za(a){const b=Array(a.length);for(let c=0,d;c=this.A&&(m||!u[k])){var f=Math.min(p/d*q|0,q),g="";switch(this.B){case "full":if(3h;n--)g=k.substring(h,n),g.length>=this.A&&M(this,u,g,l,a,c)}break}case "reverse":if(2=this.A&&M(this,u,g,f,a,c);g=""}case "forward":if(1=this.A&&M(this,u,g,f,a,c);break;default:if(M(this,u,k,f,a,c),m&&1=this.A&&!e[k]?(e[k]=1,l=this.F&&k>f,M(this,t,l?f:k,0,a,c,l?k:f)):g=Math.min(g+1,d-q)}}}this.o||(this.register[a]=1)}return this}; +function M(a,b,c,d,e,f,g){let h=g?a.h:a.map;if(!b[c]||g&&!b[c][g])a.s&&(h=h[d]),g?(b=b[c]||(b[c]=y()),b[g]=1,h=h[g]||(h[g]=y())):b[c]=1,h=h[c]||(h[c]=[]),a.s||(h=h[d]||(h[d]=[])),f&&-1!==h.indexOf(e)||(h[h.length]=e,a.o&&(a=a.register[e]||(a.register[e]=[]),a[a.length]=h))} +r.search=function(a,b,c){D(a)?(c=a,a=c.query):D(b)&&(c=b);let d=[],e;let f,g=0;if(c){b=c.limit;g=c.offset||0;var h=c.context;f=c.suggest}if(a&&(a=this.encode(a),e=a.length,1=this.A&&!c[t])if(this.s||f||this.map[t])l[u++]=t,c[t]=1;else return d;a=l;e=a.length}if(!e)return d;b||(b=100);h=this.depth&&1=d)))break;if(p){if(f)return sa(l,d,0);b[b.length]=l;return}}return!c&&l}function sa(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function ta(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}r.contain=function(a){return!!this.register[a]};r.update=function(a,b){return this.remove(a).add(a,b)}; +r.remove=function(a,b){const c=this.register[a];if(c){if(this.o)for(let d=0,e;db||c)e=e.slice(c,c+b);d&&(e=ya.call(this,e));return{tag:a,result:e}}}function ya(a){const b=Array(a.length);for(let c=0,d;c=b)return f.concat(l.slice(c,b-h+c));f=f.concat(c? -l.slice(c):l);h+=p;c=0}return f}function ja(a,b){const c=y(),e=y(),d=[];for(let f=0;f=d&&(f=d-1);this.A=d;this.threshold=f;this.F=b=c&&c.H||a.tokenize||"strict";this.depth="strict"===b&&h.depth;this.G=v(h.bidirectional,!0);this.s=g="memory"===a.optimize; -this.D=v(a.fastupdate,!0);this.o=a.minlength||1;this.h=g?w(d-f):y();d=h.resolution||d;f=h.threshold||f;f>=d&&(f=d-1);this.l=d;this.B=f;this.m=g?w(d-f):y();this.C=c&&c.C||a.rtl;this.I=(b=a.matcher||e&&e.I)&&D(b,!1);this.J=(b=a.stemmer||e&&e.J)&&D(b,!0);if(a=b=a.filter||e&&e.filter){a=b;c=y();for(let k=0,l=a.length;k=this.o&&(p||!q[n])){var f=Math.min(this.A/e*m|0,m);if(fh;l--)g=n.substring(h,l),g.length>=this.o&&R(this,q,g,k,a,c)}break}case "reverse":if(2< -d){for(h=d-1;0=this.o&&R(this,q,g,f,a,c);g=""}case "forward":if(1=this.o&&R(this,q,g,f,a,c);break;default:if(R(this,q,n,f,a,c),p&&1=this.o&&!f[n]){if(f[n]=1,l=Math.min((this.l-h)/e*m+k|0,m+(k-1)),lg;R(this,t,x?g:n,l,a,c,x?n:g)}}else h=Math.min(h+1,e-m)}}}}this.D||(this.register[a]=1)}return this}; -function R(a,b,c,e,d,f,g){let h=g?a.m:a.h;if(!b[c]||g&&!b[c][g])a.s&&(h=h[e]),g?(b=b[c]||(b[c]=y()),b[g]=1,h=h[g]||(h[g]=y())):b[c]=1,h=h[c]||(h[c]=[]),a.s||(h=h[e]||(h[e]=[])),f&&-1!==h.indexOf(d)||(h[h.length]=d,a.D&&(a=a.register[d]||(a.register[d]=[]),a[a.length]=h))} -u.search=function(a,b,c){B(a)?(c=a,a=c.query):B(b)&&(c=b);let e=[],d;var f=this.threshold;let g,h=0;if(c){b=c.limit;h=c.offset||0;f=v(c.threshold,f);var k=c.context;g=c.suggest}if(a&&(a=this.encode(a),d=a.length,1=this.o&&!c[t])if(this.s||g||this.h[t])l[q++]=t,c[t]=1;else return e;a=l;d=a.length}if(!d)return e;b||(b=100);c=this.A-f;f=this.l-f;k=this.depth&&1=d)));q++);if(r){if(g)return ma(l,d,0);b[b.length]=l;return}}return!c&&l}function ma(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} -function na(a,b,c,e){c?(e=e&&b>c,a=(a=a[e?b:c])&&a[e?c:b]):a=a[b];return a}u.contain=function(a){return!!this.register[a]};u.update=function(a,b){return this.remove(a).add(a,b)};u.remove=function(a,b){const c=this.register[a];if(c){if(this.D)for(let e=0,d;eb||c)d=d.slice(c,c+b);e&&(d=qa.call(this,d));return{tag:a,result:d}}}function qa(a){const b=Array(a.length);for(let c=0,e;c=this.m&&(m||!t[k])){var f=Math.min(p/e*q|0,q),h="";switch(this.G){case "full":if(3g;n--)h=k.substring(g,n),h.length>=this.m&&Q(this,t,h,l,a,c)}break}case "reverse":if(2=this.m&&Q(this,t,h,f,a,c);h=""}case "forward":if(1=this.m&&Q(this,t,h,f,a,c);break;default:if(Q(this,t,k,f,a,c),m&&1=this.m&&!d[k]?(d[k]=1,l=this.D&&k>f,Q(this,r,l?f:k,0,a,c,l?k:f)):h=Math.min(h+1,e-q)}}}this.B||(this.register[a]=1)}return this}; +function Q(a,b,c,e,d,f,h){let g=h?a.l:a.h;if(!b[c]||h&&!b[c][h])a.o&&(g=g[e]),h?(b=b[c]||(b[c]=z()),b[h]=1,g=g[h]||(g[h]=z())):b[c]=1,g=g[c]||(g[c]=[]),a.o||(g=g[e]||(g[e]=[])),f&&-1!==g.indexOf(d)||(g[g.length]=d,a.B&&(a=a.register[d]||(a.register[d]=[]),a[a.length]=g))} +u.search=function(a,b,c){D(a)?(c=a,a=c.query):D(b)&&(c=b);let e=[],d;let f,h=0;if(c){b=c.limit;h=c.offset||0;var g=c.context;f=c.suggest}if(a&&(a=this.encode(a),d=a.length,1=this.m&&!c[r])if(this.o||f||this.h[r])l[t++]=r,c[r]=1;else return e;a=l;d=a.length}if(!d)return e;b||(b=100);g=this.depth&&1=e)))break;if(p){if(f)return la(l,e,0);b[b.length]=l;return}}return!c&&l}function la(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function ma(a,b,c,e){c?(e=e&&b>c,a=(a=a[e?b:c])&&a[e?c:b]):a=a[b];return a}u.contain=function(a){return!!this.register[a]};u.update=function(a,b){return this.remove(a).add(a,b)};u.remove=function(a,b){const c=this.register[a];if(c){if(this.B)for(let e=0,d;eb||c)d=d.slice(c,c+b);e&&(d=pa.call(this,d));return{tag:a,result:d}}}function pa(a){const b=Array(a.length);for(let c=0,e;c= b) { - return f.concat(l.slice(c, b - h + c)); - } - f = f.concat(c ? l.slice(c) : l); - h += p; - c = 0; - } - } } return f; } @@ -154,18 +177,18 @@ function ja(a, b) { } return e; } -;function K(a) { +;function L(a) { this.limit = !0 !== a && a; this.cache = w(); this.queue = []; } function ka(a, b, c) { - z(a) && (a = a.query); + A(a) && (a = a.query); let d = this.cache.get(a); d || (d = this.search(a, b, c), this.cache.set(a, d)); return d; } -K.prototype.set = function(a, b) { +L.prototype.set = function(a, b) { if (!this.cache[a]) { var c = this.queue.length; c === this.limit ? delete this.cache[this.queue[c - 1]] : c++; @@ -176,7 +199,7 @@ K.prototype.set = function(a, b) { } this.cache[a] = b; }; -K.prototype.get = function(a) { +L.prototype.get = function(a) { const b = this.cache[a]; if (this.limit && b && (a = this.queue.indexOf(a))) { const c = this.queue[a - 1]; @@ -185,13 +208,13 @@ K.prototype.get = function(a) { } return b; }; -K.prototype.del = function(a) { +L.prototype.del = function(a) { for (let b = 0, c, d; b < this.queue.length; b++) { d = this.queue[b], c = this.cache[d], -1 !== c.indexOf(a) && (this.queue.splice(b--, 1), delete this.cache[d]); } }; const la = {memory:{charset:"latin:extra", resolution:3, minlength:3, fastupdate:!1, optimize:"memory"}, performance:{threshold:8, minlength:3, context:{depth:1, bidirectional:!0}}, match:{charset:"latin:extra", tokenize:"full", resolution:3, }, score:{charset:"latin:advanced", threshold:1, context:{depth:3, bidirectional:!0}}, "default":{resolution:3, threshold:0, depth:3}, }; -function oa(a, b, c, d, e, f) { +function na(a, b, c, d, e, f) { setTimeout(function() { const g = a(c, JSON.stringify(f)); g && g.then ? g.then(function() { @@ -199,14 +222,14 @@ function oa(a, b, c, d, e, f) { }) : b.export(a, b, c, d, e + 1); }); } -;I["latin:default"] = da; -function L(a, b) { - if (!(this instanceof L)) { - return new L(a); +;J["latin:default"] = ea; +function M(a, b) { + if (!(this instanceof M)) { + return new M(a); } var c; if (a) { - if (x(a)) { + if (y(a)) { la[a] || console.warn("Preset not found: " + a), a = la[a]; } else { if (c = a.preset) { @@ -215,48 +238,40 @@ function L(a, b) { } c = a.charset; var d = a.lang; - x(c) && (-1 === c.indexOf(":") && (c += ":default"), c = I[c]); - x(d) && (d = ea[d]); + y(c) && (-1 === c.indexOf(":") && (c += ":default"), c = J[c]); + y(d) && (d = fa[d]); } else { a = {}; } - let e, f, g, h = a.context || {}; - this.encode = a.encode || c && c.encode || da; + let e, f, g = a.context || {}; + this.encode = a.encode || c && c.encode || ea; this.register = b || w(); - e = a.resolution || 9; - f = a.threshold || 0; - f >= e && (f = e - 1); - this.resolution = e; - this.threshold = f; + this.resolution = e = a.resolution || 9; this.tokenizer = b = c && c.tokenize || a.tokenize || "strict"; - this.depth = "strict" === b && h.depth; - this.bidirectional = t(h.bidirectional, !0); - this.optimize = g = "memory" === a.optimize; + this.depth = "strict" === b && g.depth; + this.bidirectional = t(g.bidirectional, !0); + this.optimize = f = "memory" === a.optimize; this.fastupdate = t(a.fastupdate, !0); this.minlength = a.minlength || 1; - this.map = g ? v(e - f) : w(); - e = h.resolution || e; - f = h.threshold || f; - f >= e && (f = e - 1); - this.resolution_ctx = e; - this.threshold_ctx = f; - this.ctx = g ? v(e - f) : w(); + this.map = f ? v(e) : w(); + this.resolution_ctx = e = g.resolution || 1; + this.ctx = f ? v(e) : w(); this.rtl = c && c.rtl || a.rtl; - this.matcher = (b = a.matcher || d && d.matcher) && D(b, !1); - this.stemmer = (b = a.stemmer || d && d.stemmer) && D(b, !0); + this.matcher = (b = a.matcher || d && d.matcher) && ca(b, !1); + this.stemmer = (b = a.stemmer || d && d.stemmer) && ca(b, !0); if (c = b = a.filter || d && d.filter) { c = b; d = w(); - for (let k = 0, l = c.length; k < l; k++) { - d[c[k]] = 1; + for (let h = 0, k = c.length; h < k; h++) { + d[c[h]] = 1; } c = d; } this.filter = c; - this.cache = (b = a.cache) && new K(b); + this.cache = (b = a.cache) && new L(b); } -L.prototype.pipeline = function(a, b, c, d) { - if (a && (b && (a = F(a, b)), this.matcher && (a = F(a, this.matcher)), this.stemmer && 1 < a.length && (a = F(a, this.stemmer)), d && 1 < a.length && (a = H(a)), c || "" === c)) { +M.prototype.pipeline = function(a, b, c, d) { + if (a && (b && (a = H(a, b)), this.matcher && (a = H(a, this.matcher)), this.stemmer && 1 < a.length && (a = H(a, this.stemmer)), d && 1 < a.length && (a = I(a)), c || "" === c)) { a = a.split(c); if (this.filter) { b = this.filter; @@ -272,63 +287,51 @@ L.prototype.pipeline = function(a, b, c, d) { } return a; }; -L.prototype.append = function(a, b) { +M.prototype.append = function(a, b) { return this.add(a, b, !0); }; -L.prototype.add = function(a, b, c, d) { +M.prototype.add = function(a, b, c, d) { if (!d && !c && this.register[a]) { return this.update(a, b); } if (b && (a || 0 === a) && (b = this.encode(b), d = b.length)) { - const p = this.depth, u = this.resolution - this.threshold, r = w(), q = w(); - for (let n = 0; n < d; n++) { - let m = b[this.rtl ? d - 1 - n : n]; - var e = m.length; - if (m && e >= this.minlength && (p || !r[m])) { - var f = Math.min(this.resolution / d * n | 0, n); - if (f < u) { - var g = ""; - switch(this.tokenizer) { - case "full": - if (3 < e) { - for (var h = 0; h < e; h++) { - var k = h ? Math.min(f / 2 + this.resolution / e * h / 2 | 0, f + h) : f; - if (k < u) { - for (var l = e; l > h; l--) { - g = m.substring(h, l), g.length >= this.minlength && this.push_index(r, g, k, a, c); - } - } - } - break; - } - case "reverse": - if (2 < e) { - for (h = e - 1; 0 < h; h--) { - g = m[h] + g, g.length >= this.minlength && this.push_index(r, g, f, a, c); - } - g = ""; - } - case "forward": - if (1 < e) { - for (h = 0; h < e; h++) { - g += m[h], g.length >= this.minlength && this.push_index(r, g, f, a, c); + const m = this.depth, n = this.resolution, r = w(), u = w(); + for (let p = 0; p < d; p++) { + let l = b[this.rtl ? d - 1 - p : p]; + var e = l.length; + if (l && e >= this.minlength && (m || !r[l])) { + var f = Math.min(n / d * p | 0, p), g = ""; + switch(this.tokenizer) { + case "full": + if (3 < e) { + for (var h = 0; h < e; h++) { + var k = h ? Math.min(f / 2 + n / e * h / 2 | 0, f + h) : f; + for (let q = e; q > h; q--) { + g = l.substring(h, q), g.length >= this.minlength && this.push_index(r, g, k, a, c); } } break; - default: - if (this.push_index(r, m, f, a, c), p && 1 < d && n < d - 1) { - for (e = this.resolution_ctx - this.threshold_ctx, f = w(), g = m, h = Math.min(p + 1, d - n), f[g] = 1, k = 1; k < h; k++) { - if ((m = b[this.rtl ? d - 1 - n - k : n + k]) && m.length >= this.minlength && !f[m]) { - if (f[m] = 1, l = Math.min((this.resolution_ctx - h) / d * n + k | 0, n + (k - 1)), l < e) { - const y = this.bidirectional && m > g; - this.push_index(q, y ? g : m, l, a, c, y ? m : g); - } - } else { - h = Math.min(h + 1, d - n); - } - } + } + case "reverse": + if (2 < e) { + for (h = e - 1; 0 < h; h--) { + g = l[h] + g, g.length >= this.minlength && this.push_index(r, g, f, a, c); } - } + g = ""; + } + case "forward": + if (1 < e) { + for (h = 0; h < e; h++) { + g += l[h], g.length >= this.minlength && this.push_index(r, g, f, a, c); + } + } + break; + default: + if (this.push_index(r, l, f, a, c), m && 1 < d && p < d - 1) { + for (e = w(), f = l, g = Math.min(m + 1, d - p), e[f] = 1, h = 1; h < g; h++) { + (l = b[this.rtl ? d - 1 - p - h : p + h]) && l.length >= this.minlength && !e[l] ? (e[l] = 1, k = this.bidirectional && l > f, this.push_index(u, k ? f : l, 0, a, c, k ? l : f)) : g = Math.min(g + 1, d - p); + } + } } } } @@ -336,105 +339,106 @@ L.prototype.add = function(a, b, c, d) { } return this; }; -L.prototype.push_index = function(a, b, c, d, e, f) { +M.prototype.push_index = function(a, b, c, d, e, f) { let g = f ? this.ctx : this.map; if (!a[b] || f && !a[b][f]) { this.optimize && (g = g[c]), f ? (a = a[b] || (a[b] = w()), a[f] = 1, g = g[f] || (g[f] = w())) : a[b] = 1, g = g[b] || (g[b] = []), this.optimize || (g = g[c] || (g[c] = [])), e && -1 !== g.indexOf(d) || (g[g.length] = d, this.fastupdate && (a = this.register[d] || (this.register[d] = []), a[a.length] = g)); } }; -L.prototype.search = function(a, b, c) { - z(a) ? (c = a, a = c.query) : z(b) && (c = b); +M.prototype.search = function(a, b, c) { + A(a) ? (c = a, a = c.query) : A(b) && (c = b); let d = [], e; - var f = this.threshold; - let g, h = 0; + let f, g = 0; if (c) { b = c.limit; - h = c.offset || 0; - f = t(c.threshold, f); - var k = c.context; - g = c.suggest; + g = c.offset || 0; + var h = c.context; + f = c.suggest; } if (a && (a = this.encode(a), e = a.length, 1 < e)) { c = w(); - var l = []; - for (let u = 0, r = 0, q; u < e; u++) { - if ((q = a[u]) && q.length >= this.minlength && !c[q]) { - if (this.optimize || g || this.map[q]) { - l[r++] = q, c[q] = 1; + var k = []; + for (let n = 0, r = 0, u; n < e; n++) { + if ((u = a[n]) && u.length >= this.minlength && !c[u]) { + if (this.optimize || f || this.map[u]) { + k[r++] = u, c[u] = 1; } else { return d; } } } - a = l; + a = k; e = a.length; } if (!e) { return d; } b || (b = 100); - c = this.resolution - f; - f = this.resolution_ctx - f; - k = this.depth && 1 < e && !1 !== k; - l = 0; - let p; - k ? (p = a[0], l = 1) : 1 < e && a.sort(aa); - for (let u, r; l < e; l++) { - r = a[l]; - k ? (u = this.add_result(d, g, f, b, h, 2 === e, r, p), g && !1 === u && d.length || (p = r)) : u = this.add_result(d, g, c, b, h, 1 === e, r); - if (u) { - return u; + h = this.depth && 1 < e && !1 !== h; + c = 0; + let m; + h ? (m = a[0], c = 1) : 1 < e && a.sort(aa); + for (let n, r; c < e; c++) { + r = a[c]; + h ? (n = this.add_result(d, f, b, g, 2 === e, r, m), f && !1 === n && d.length || (m = r)) : n = this.add_result(d, f, b, g, 1 === e, r); + if (n) { + return n; } - if (g && l === e - 1) { - let q = d.length; - if (!q) { - if (k) { - k = 0; - l = -1; + if (f && c === e - 1) { + k = d.length; + if (!k) { + if (h) { + h = 0; + c = -1; continue; } return d; } - if (1 === q) { - return pa(d[0], b, h); + if (1 === k) { + return oa(d[0], b, g); } } } - return ia(d, b, h, g); + return ia(d, b, g, f); }; -L.prototype.add_result = function(a, b, c, d, e, f, g, h) { - let k = [], l = h ? this.ctx : this.map; - this.optimize || (l = qa(l, g, h, this.bidirectional)); - if (l) { - let p = 0; - c = Math.min(l.length, c); - for (let u = 0, r = 0, q, n; u < c && !(q = l[u], this.optimize && (q = qa(q, g, h, this.bidirectional)), q && f && (n = q.length, n <= e ? (e -= n, q = null) : e && (q = q.slice(e), e = 0)), q && (k[p++] = q, f && (r += q.length, r >= d))); u++) { - } - if (p) { - if (f) { - return pa(k, d, 0); +M.prototype.add_result = function(a, b, c, d, e, f, g) { + let h = [], k = g ? this.ctx : this.map; + this.optimize || (k = pa(k, f, g, this.bidirectional)); + if (k) { + let m = 0; + const n = Math.min(k.length, g ? this.resolution_ctx : this.resolution); + for (let r = 0, u = 0, p, l; r < n; r++) { + if (p = k[r]) { + if (this.optimize && (p = pa(p, f, g, this.bidirectional)), d && p && e && (l = p.length, l <= d ? (d -= l, p = null) : (p = p.slice(d), d = 0)), p && (h[m++] = p, e && (u += p.length, u >= c))) { + break; + } } - a[a.length] = k; + } + if (m) { + if (e) { + return oa(h, c, 0); + } + a[a.length] = h; return; } } - return !b && k; + return !b && h; }; -function pa(a, b, c) { +function oa(a, b, c) { a = 1 === a.length ? a[0] : [].concat.apply([], a); return c || a.length > b ? a.slice(c, c + b) : a; } -function qa(a, b, c, d) { +function pa(a, b, c, d) { c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; return a; } -L.prototype.contain = function(a) { +M.prototype.contain = function(a) { return !!this.register[a]; }; -L.prototype.update = function(a, b) { +M.prototype.update = function(a, b) { return this.remove(a).add(a, b); }; -L.prototype.remove = function(a, b) { +M.prototype.remove = function(a, b) { const c = this.register[a]; if (c) { if (this.fastupdate) { @@ -442,14 +446,14 @@ L.prototype.remove = function(a, b) { e = c[d], e.splice(e.indexOf(a), 1); } } else { - N(this.map, a, this.resolution - this.threshold, this.optimize), this.depth && N(this.ctx, a, this.resolution_ctx - this.threshold_ctx, this.optimize); + O(this.map, a, this.resolution, this.optimize), this.depth && O(this.ctx, a, this.resolution_ctx, this.optimize); } b || delete this.register[a]; this.cache && this.cache.del(a); } return this; }; -function N(a, b, c, d, e) { +function O(a, b, c, d, e) { let f = 0; if (a.constructor === Array) { if (e) { @@ -458,19 +462,19 @@ function N(a, b, c, d, e) { e = Math.min(a.length, c); for (let g = 0, h; g < e; g++) { if (h = a[g]) { - f = N(h, b, c, d, e), d || f || delete a[g]; + f = O(h, b, c, d, e), d || f || delete a[g]; } } } } else { for (let g in a) { - (f = N(a[g], b, c, d, e)) || delete a[g]; + (f = O(a[g], b, c, d, e)) || delete a[g]; } } return f; } -L.prototype.searchCache = ka; -L.prototype.export = function(a, b, c, d, e) { +M.prototype.searchCache = ka; +M.prototype.export = function(a, b, c, d, e) { let f, g; switch(e || (e = 0)) { case 0: @@ -499,12 +503,12 @@ L.prototype.export = function(a, b, c, d, e) { default: return; } - oa(a, b || this, c ? c + "." + f : f, d, e, g); + na(a, b || this, c ? c + "." + f : f, d, e, g); return !0; }; -L.prototype.import = function(a, b) { +M.prototype.import = function(a, b) { if (b) { - switch(x(b) && (b = JSON.parse(b)), a) { + switch(y(b) && (b = JSON.parse(b)), a) { case "cfg": this.optimize = !!b.opt; break; @@ -520,8 +524,8 @@ L.prototype.import = function(a, b) { } } }; -ha(L.prototype); -function ra(a) { +ha(M.prototype); +function qa(a) { a = a.data; var b = self._index; const c = a.args; @@ -533,19 +537,19 @@ function ra(a) { b = d.encode; d.cache = !1; b && 0 === b.indexOf("function") && (d.encode = Function("return " + b)()); - a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new L(d); + a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new M(d); break; default: a = a.id, b = b[d].apply(b, c), postMessage("search" === d ? {id:a, msg:b} : {id:a}); } } -;let sa = 0; -function O(a) { +;let ra = 0; +function P(a) { var b; - a ? B(b = a.encode) && (a.encode = b.toString()) : a = {}; + a ? D(b = a.encode) && (a.encode = b.toString()) : a = {}; (b = (self || window)._factory) && (b = b.toString()); const c = self.exports, d = this; - this.worker = ta(b, c, a.worker); + this.worker = sa(b, c, a.worker); this.resolver = w(); if (this.worker) { if (c) { @@ -563,68 +567,67 @@ function O(a) { this.worker.postMessage({task:"init", factory:b, options:a}); } } -P("add"); -P("append"); -P("search"); -P("update"); -P("remove"); -function P(a) { - O.prototype[a] = O.prototype[a + "Async"] = function() { +Q("add"); +Q("append"); +Q("search"); +Q("update"); +Q("remove"); +function Q(a) { + P.prototype[a] = P.prototype[a + "Async"] = function() { const b = this, c = [].slice.call(arguments); var d = c[c.length - 1]; let e; - B(d) && (e = d, c.splice(c.length - 1, 1)); - d = new fa(function(f) { + D(d) && (e = d, c.splice(c.length - 1, 1)); + d = new Promise(function(f) { setTimeout(function() { - b.resolver[++sa] = f; - b.worker.postMessage({task:a, id:sa, args:c}); + b.resolver[++ra] = f; + b.worker.postMessage({task:a, id:ra, args:c}); }); }); return e ? (d.then(e), this) : d; }; } -function ta(a, b, c) { +function sa(a, b, c) { let d; try { - d = b ? eval('new (require("worker_threads")["Worker"])("../dist/node/node.js")') : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + ra.toString()], {type:"text/javascript"}))) : new Worker(x(c) ? c : "worker/worker.js", {type:"module"}); + d = b ? eval('new (require("worker_threads")["Worker"])("../dist/node/node.js")') : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + qa.toString()], {type:"text/javascript"}))) : new Worker(y(c) ? c : "worker/worker.js", {type:"module"}); } catch (e) { } return d; } -;function Q(a) { - if (!(this instanceof Q)) { - return new Q(a); +;function R(a) { + if (!(this instanceof R)) { + return new R(a); } var b = a.document || a.doc || a, c; this.tree = []; this.field = []; this.marker = []; this.register = w(); - this.key = (c = b.key || b.id) && R(c, this.marker) || "id"; + this.key = (c = b.key || b.id) && S(c, this.marker) || "id"; this.fastupdate = t(a.fastupdate, !0); - this.extern = !!(c = b.extern); - this.storetree = !this.extern && (c = b.store) && !0 !== c && []; - this.store = c && (this.extern ? c : w()); - this.tag = (c = b.tag) && R(c, this.marker); + this.storetree = (c = b.store) && !0 !== c && []; + this.store = c && w(); + this.tag = (c = b.tag) && S(c, this.marker); this.tagindex = c && w(); - this.cache = (c = a.cache) && new K(c); + this.cache = (c = a.cache) && new L(c); a.cache = !1; this.worker = a.worker; this.async = !1; c = w(); let d = b.index || b.field || b; - x(d) && (d = [d]); + y(d) && (d = [d]); for (let e = 0, f, g; e < d.length; e++) { - f = d[e], x(f) || (g = f, f = f.field), g = z(g) ? Object.assign({}, a, g) : a, this.worker && (c[f] = new O(g), c[f].worker || (this.worker = !1)), this.worker || (c[f] = new L(g, this.register)), this.tree[e] = R(f, this.marker), this.field[e] = f; + f = d[e], y(f) || (g = f, f = f.field), g = A(g) ? Object.assign({}, a, g) : a, this.worker && (c[f] = new P(g), c[f].worker || (this.worker = !1)), this.worker || (c[f] = new M(g, this.register)), this.tree[e] = S(f, this.marker), this.field[e] = f; } if (this.storetree) { - for (a = b.store, x(a) && (a = [a]), b = 0; b < a.length; b++) { - this.storetree[b] = R(a[b], this.marker); + for (a = b.store, y(a) && (a = [a]), b = 0; b < a.length; b++) { + this.storetree[b] = S(a[b], this.marker); } } this.index = c; } -function R(a, b) { +function S(a, b) { const c = a.split(":"); let d = 0; for (let e = 0; e < c.length; e++) { @@ -633,8 +636,8 @@ function R(a, b) { d < c.length && (c.length = d); return 1 < d ? c : c[0]; } -function S(a, b) { - if (x(b)) { +function T(a, b) { + if (y(b)) { a = a[b]; } else { for (let c = 0; a && c < b.length; c++) { @@ -643,7 +646,7 @@ function S(a, b) { } return a; } -function V(a, b, c, d, e) { +function U(a, b, c, d, e) { a = a[e]; if (d === c.length - 1) { b[e] = a; @@ -651,10 +654,10 @@ function V(a, b, c, d, e) { if (a) { if (a.constructor === Array) { for (b = b[e] = Array(a.length), e = 0; e < a.length; e++) { - V(a, b, c, d, e); + U(a, b, c, d, e); } } else { - b = b[e] || (b[e] = w()), e = c[++d], V(a, b, c, d, e); + b = b[e] || (b[e] = w()), e = c[++d], U(a, b, c, d, e); } } } @@ -684,18 +687,18 @@ function W(a, b, c, d, e, f, g, h) { } } } -Q.prototype.add = function(a, b, c) { - z(a) && (b = a, a = S(b, this.key)); +R.prototype.add = function(a, b, c) { + A(a) && (b = a, a = T(b, this.key)); if (b && (a || 0 === a)) { if (this.register[a]) { return this.update(a, b); } for (let d = 0, e, f; d < this.field.length; d++) { - f = this.field[d], e = this.tree[d], x(e) && (e = [e]), W(b, e, this.marker, 0, this.index[f], a, e[0], c); + f = this.field[d], e = this.tree[d], y(e) && (e = [e]), W(b, e, this.marker, 0, this.index[f], a, e[0], c); } if (this.tag) { - let d = S(b, this.tag), e = w(); - x(d) && (d = [d]); + let d = T(b, this.tag), e = w(); + y(d) && (d = [d]); for (let f = 0, g, h; f < d.length; f++) { if (g = d[f], !e[g] && (e[g] = 1, h = this.tagindex[g] || (this.tagindex[g] = []), !c || -1 === h.indexOf(a))) { if (h[h.length] = a, this.fastupdate) { @@ -705,12 +708,12 @@ Q.prototype.add = function(a, b, c) { } } } - if (this.store && !this.extern) { + if (this.store) { let d; if (this.storetree) { d = w(); for (let e = 0, f; e < this.storetree.length; e++) { - f = this.storetree[e], x(f) ? d[f] = b[f] : V(b, d, f, 0, f[0]); + f = this.storetree[e], y(f) ? d[f] = b[f] : U(b, d, f, 0, f[0]); } } this.store[a] = d || b; @@ -718,14 +721,14 @@ Q.prototype.add = function(a, b, c) { } return this; }; -Q.prototype.append = function(a, b) { +R.prototype.append = function(a, b) { return this.add(a, b, !0); }; -Q.prototype.update = function(a, b) { +R.prototype.update = function(a, b) { return this.remove(a).add(a, b); }; -Q.prototype.remove = function(a) { - z(a) && (a = S(a, this.key)); +R.prototype.remove = function(a) { + A(a) && (a = T(a, this.key)); if (this.register[a]) { var b = this.fastupdate && !this.worker; for (var c = 0; c < this.field.length && (this.index[this.field[c]].remove(a, b), !b); c++) { @@ -735,119 +738,119 @@ Q.prototype.remove = function(a) { b = this.tagindex[d], c = b.indexOf(a), -1 !== c && (1 < b.length ? b.splice(c, 1) : delete this.tagindex[d]); } } - this.store && !this.extern && delete this.store[a]; + this.store && delete this.store[a]; delete this.register[a]; } return this; }; -Q.prototype.search = function(a, b, c, d) { - z(a) ? (c = a, a = c.query) : z(b) && (c = b, b = 0); - let e = [], f = [], g, h, k, l, p, u, r = 0; +R.prototype.search = function(a, b, c, d) { + A(a) ? (c = a, a = c.query) : A(b) && (c = b, b = 0); + let e = [], f = [], g, h, k, m, n, r, u = 0; if (c) { if (c.constructor === Array) { k = c, c = null; } else { k = (g = c.pluck) || c.index || c.field || c; - l = c.tag; + m = c.tag; h = this.store && c.enrich; - p = "and" === c.bool; + n = "and" === c.bool; b = c.limit || 100; - u = c.offset || 0; - if (l && (x(l) && (l = [l]), !a)) { - for (let n = 0, m; n < l.length; n++) { - if (m = ua.call(this, l[n], b, u, h)) { - e[e.length] = m, r++; + r = c.offset || 0; + if (m && (y(m) && (m = [m]), !a)) { + for (let l = 0, q; l < m.length; l++) { + if (q = ta.call(this, m[l], b, r, h)) { + e[e.length] = q, u++; } } - return r ? e : []; + return u ? e : []; } - x(k) ? k = [k] : k.constructor === Array || (k = null); + y(k) ? k = [k] : k.constructor === Array || (k = null); } } k || (k = this.field); - p = p && (1 < k.length || l && 1 < l.length); - const q = !d && (this.worker || this.async) && []; - for (let n = 0, m, y, A; n < k.length; n++) { - let T; - y = k[n]; - x(y) || (T = y, y = y.field); - if (q) { - q[n] = this.index[y].searchAsync(a, b, T || c); + n = n && (1 < k.length || m && 1 < m.length); + const p = !d && (this.worker || this.async) && []; + for (let l = 0, q, x, z; l < k.length; l++) { + let B; + x = k[l]; + y(x) || (B = x, x = x.field); + if (p) { + p[l] = this.index[x].searchAsync(a, b, B || c); } else { - A = (m = d ? d[n] : this.index[y].search(a, b, T || c)) && m.length; - if (l && A) { - const G = []; - let ma = 0; - p && (G[0] = [m]); - for (let U = 0, na, M; U < l.length; U++) { - if (na = l[U], A = (M = this.tagindex[na]) && M.length) { - ma++, G[G.length] = p ? [M] : M; + z = (q = d ? d[l] : this.index[x].search(a, b, B || c)) && q.length; + if (m && z) { + const C = []; + let G = 0; + n && (C[0] = [q]); + for (let V = 0, ma, N; V < m.length; V++) { + if (ma = m[V], z = (N = this.tagindex[ma]) && N.length) { + G++, C[C.length] = n ? [N] : N; } } - ma && (m = p ? ia(G, b || 100, u || 0) : ja(m, G), A = m.length); + G && (q = n ? ia(C, b || 100, r || 0) : ja(q, C), z = q.length); } - if (A) { - f[r] = y, e[r++] = m; + if (z) { + f[u] = x, e[u++] = q; } else { - if (p) { + if (n) { return []; } } } } - if (q) { - const n = this; - return new Promise(function(m) { - Promise.all(q).then(function(y) { - m(n.search(a, b, c, y)); + if (p) { + const l = this; + return new Promise(function(q) { + Promise.all(p).then(function(x) { + q(l.search(a, b, c, x)); }); }); } - if (!r) { + if (!u) { return []; } if (g && (!h || !this.store)) { return e[0]; } - for (let n = 0, m; n < f.length; n++) { - m = e[n]; - m.length && h && (m = va.call(this, m)); + for (let l = 0, q; l < f.length; l++) { + q = e[l]; + q.length && h && (q = ua.call(this, q)); if (g) { - return m; + return q; } - e[n] = {field:f[n], result:m}; + e[l] = {field:f[l], result:q}; } return e; }; -function ua(a, b, c, d) { +function ta(a, b, c, d) { let e = this.tagindex[a], f = e && e.length - c; if (f && 0 < f) { if (f > b || c) { e = e.slice(c, c + b); } - d && (e = va.call(this, e)); + d && (e = ua.call(this, e)); return {tag:a, result:e}; } } -function va(a) { +function ua(a) { const b = Array(a.length); for (let c = 0, d; c < a.length; c++) { d = a[c], b[c] = {key:d, doc:this.store[d]}; } return b; } -Q.prototype.contain = function(a) { +R.prototype.contain = function(a) { return !!this.register[a]; }; -Q.prototype.get = function(a) { +R.prototype.get = function(a) { return this.store[a]; }; -Q.prototype.set = function(a, b) { +R.prototype.set = function(a, b) { this.store[a] = b; return this; }; -Q.prototype.searchCache = ka; -Q.prototype.export = function(a, b, c, d, e) { +R.prototype.searchCache = ka; +R.prototype.export = function(a, b, c, d, e) { e || (e = 0); d || (d = 0); if (d < this.field.length) { @@ -870,12 +873,12 @@ Q.prototype.export = function(a, b, c, d, e) { default: return; } - oa(a, this, c, d, e, f); + na(a, this, c, d, e, f); } }; -Q.prototype.import = function(a, b) { +R.prototype.import = function(a, b) { if (b) { - switch(x(b) && (b = JSON.parse(b)), a) { + switch(y(b) && (b = JSON.parse(b)), a) { case "tag": this.tagindex = b; break; @@ -897,27 +900,27 @@ Q.prototype.import = function(a, b) { } } }; -ha(Q.prototype); -var xa = {encode:wa, rtl:!1, tokenize:""}; -const ya = /[\W_]+/, za = E("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), Aa = E("[\u00e8\u00e9\u00ea\u00eb]"), Ba = E("[\u00ec\u00ed\u00ee\u00ef]"), Ca = E("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), Da = E("[\u00f9\u00fa\u00fb\u00fc\u0171]"), Ea = E("[\u00fd\u0177\u00ff]"), Fa = E("\u00f1"), Ga = E("[\u00e7c]"), Ha = E("\u00df"), Ia = E(" & "), Ja = [za, "a", Aa, "e", Ba, "i", Ca, "o", Da, "u", Ea, "y", Fa, "n", Ga, "k", Ha, "s", Ia, " and "]; -function wa(a) { - return this.pipeline(C(a).toLowerCase(), !a.normalize && Ja, ya, !1); +ha(R.prototype); +var wa = {encode:va, rtl:!1, tokenize:""}; +const xa = /[\W_]+/, ya = F("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), za = F("[\u00e8\u00e9\u00ea\u00eb]"), Aa = F("[\u00ec\u00ed\u00ee\u00ef]"), Ba = F("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), Ca = F("[\u00f9\u00fa\u00fb\u00fc\u0171]"), Da = F("[\u00fd\u0177\u00ff]"), Ea = F("\u00f1"), Fa = F("[\u00e7c]"), Ga = F("\u00df"), Ha = F(" & "), Ia = [ya, "a", za, "e", Aa, "i", Ba, "o", Ca, "u", Da, "y", Ea, "n", Fa, "k", Ga, "s", Ha, " and "]; +function va(a) { + return this.pipeline(E(a).toLowerCase(), !a.normalize && Ia, xa, !1); } -;var La = {encode:Ka, rtl:!1, tokenize:"strict"}; -const Ma = /[^a-z0-9]+/, Na = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; -function Ka(a) { - a = wa.call(this, a).join(" "); +;var Ka = {encode:Ja, rtl:!1, tokenize:"strict"}; +const La = /[^a-z0-9]+/, Ma = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function Ja(a) { + a = va.call(this, a).join(" "); const b = []; if (a) { - const c = a.split(Ma), d = c.length; + const c = a.split(La), d = c.length; for (let e = 0, f, g = 0; e < d; e++) { if ((a = c[e]) && (!this.filter || !this.filter[a])) { f = a[0]; - let h = Na[f] || f, k = h; - for (let l = 1; l < a.length; l++) { - f = a[l]; - const p = Na[f] || f; - p && p !== k && (h += p, k = p); + let h = Ma[f] || f, k = h; + for (let m = 1; m < a.length; m++) { + f = a[m]; + const n = Ma[f] || f; + n && n !== k && (h += n, k = n); } b[g++] = h; } @@ -925,28 +928,28 @@ function Ka(a) { } return b; } -;var Pa = {encode:Oa, rtl:!1, tokenize:""}; -const Qa = E("ae"), Ra = E("oe"), Sa = E("sh"), Ta = E("th"), Ua = E("ph"), Va = E("pf"), Wa = [Qa, "a", Ra, "o", Sa, "s", Ta, "t", Ua, "f", Va, "f", ]; -function Oa(a, b) { - a && (a = Ka.call(this, a).join(" "), 2 < a.length && (a = F(a, Wa)), b || (1 < a.length && (a = H(a)), a && (a = a.split(" ")))); +;var Oa = {encode:Na, rtl:!1, tokenize:""}; +const Pa = F("ae"), Qa = F("oe"), Ra = F("sh"), Sa = F("th"), Ta = F("ph"), Ua = F("pf"), Va = [Pa, "a", Qa, "o", Ra, "s", Sa, "t", Ta, "f", Ua, "f", ]; +function Na(a, b) { + a && (a = Ja.call(this, a).join(" "), 2 < a.length && (a = H(a, Va)), b || (1 < a.length && (a = I(a)), a && (a = a.split(" ")))); return a; } -;var Ya = {encode:Xa, rtl:!1, tokenize:""}; -const Za = E("(?!\\b)[aeiouy]"); -function Xa(a) { - a && (a = Oa.call(this, a, !0), 1 < a.length && (a = a.replace(Za, "")), 1 < a.length && (a = H(a)), a && (a = a.split(" "))); +;var Xa = {encode:Wa, rtl:!1, tokenize:""}; +const Ya = F("(?!\\b)[aeiouy]"); +function Wa(a) { + a && (a = Na.call(this, a, !0), 1 < a.length && (a = a.replace(Ya, "")), 1 < a.length && (a = I(a)), a && (a = a.split(" "))); return a; } -;I["latin:simple"] = xa; -I["latin:balance"] = La; -I["latin:advanced"] = Pa; -I["latin:extra"] = Ya; +;J["latin:simple"] = wa; +J["latin:balance"] = Ka; +J["latin:advanced"] = Oa; +J["latin:extra"] = Xa; const X = self; let Y; -const Z = {Index:L, Document:Q, Worker:O, registerCharset:function(a, b) { - I[a] = b; +const Z = {Index:M, Document:R, Worker:P, registerCharset:function(a, b) { + J[a] = b; }, registerLanguage:function(a, b) { - ea[a] = b; + fa[a] = b; }}; (Y = X.define) && Y.amd ? Y([], function() { return Z; diff --git a/dist/flexsearch.es5.js b/dist/flexsearch.es5.js index 287db3f..4073183 100644 --- a/dist/flexsearch.es5.js +++ b/dist/flexsearch.es5.js @@ -6,42 +6,41 @@ * https://github.com/nextapps-de/flexsearch */ (function(self){'use strict';var u;function aa(a){var b=0;return function(){return b>>0)+"_",f=0;return b}); -z("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c=b)return g.concat(x.slice(c,b-e+c));g=g.concat(c?x.slice(c):x);e+=f;c= -0}return g}function va(a,b){for(var c=B(),d=B(),f=[],g=0;g=e&&(h=e-1);this.F=e;this.threshold=h;this.o=b=c&&c.L||a.tokenize||"strict";this.depth="strict"===b&&g.depth;this.K=A(g.bidirectional,!0);this.C=f="memory"=== -a.optimize;this.A=A(a.fastupdate,!0);this.D=a.minlength||1;this.map=f?ha(e-h):B();e=g.resolution||e;h=g.threshold||h;h>=e&&(h=e-1);this.l=e;this.m=h;this.h=f?ha(e-h):B();this.H=c&&c.H||a.rtl;this.N=(b=a.matcher||d&&d.N)&&la(b,!1);this.O=(b=a.stemmer||d&&d.O)&&la(b,!0);if(c=b=a.filter||d&&d.filter){c=b;d=B();g=0;for(e=c.length;g=this.D&&(f||!e[l])){var q=Math.min(this.F/d*k|0,k);if(qp;t--)m=l.substring(p,t),m.length>=this.D&&N(this,e,m,r,a,c)}break}case "reverse":if(2< -n){for(p=n-1;0=this.D&&N(this,e,m,q,a,c);m=""}case "forward":if(1=this.D&&N(this,e,m,q,a,c);break;default:if(N(this,e,l,q,a,c),f&&1=this.D&&!q[l]){if(q[l]=1,t=Math.min((this.l-p)/d*k+r|0,k+(r-1)),tm;N(this,h,y?m:l,t,a,c,y?l:m)}}else p=Math.min(p+1,d-k)}}}}this.A||(this.register[a]=1)}return this}; -function N(a,b,c,d,f,g,e){var h=e?a.h:a.map;if(!b[c]||e&&!b[c][e])a.C&&(h=h[d]),e?(b=b[c]||(b[c]=B()),b[e]=1,h=h[e]||(h[e]=B())):b[c]=1,h=h[c]||(h[c]=[]),a.C||(h=h[d]||(h[d]=[])),g&&-1!==h.indexOf(f)||(h[h.length]=f,a.A&&(a=a.register[f]||(a.register[f]=[]),a[a.length]=h))} -u.search=function(a,b,c){D(a)?(c=a,a=c.query):D(b)&&(c=b);var d=[],f=this.threshold,g=0;if(c){b=c.limit;g=c.offset||0;f=A(c.threshold,f);var e=c.context;var h=c.suggest}if(a){a=this.encode(a);var k=a.length;if(1=this.D&&!c[m])if(this.C||h||this.map[m])l[q++]=m,c[m]=1;else return d;a=l;k=a.length}}if(!k)return d;b||(b=100);c=this.F-f;f=this.l-f;e=this.depth&&1=f)));m++);if(q){if(e)return Aa(l,f,0);b[b.length]=l;return}}return!c&&l}function Aa(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} -function Ba(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}u.contain=function(a){return!!this.register[a]};u.update=function(a,b){return this.remove(a).add(a,b)}; -u.remove=function(a,b){var c=this.register[a];if(c){if(this.A)for(var d=0,f;db||c)f=f.slice(c,c+b);d&&(f=Ga.call(this,f));return{tag:a,result:f}}}function Ga(a){for(var b=Array(a.length),c=0,d;c>>0)+"_",f=0;return b}); +x("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c=this.D&&(f||!e[l])){var q=Math.min(h/d*k|0,k),n="";switch(this.m){case "full":if(3p;t--)n=l.substring(p,t),n.length>=this.D&&P(this,e,n,r,a,c);break}case "reverse":if(2= +this.D&&P(this,e,n,q,a,c);n=""}case "forward":if(1=this.D&&P(this,e,n,q,a,c);break;default:if(P(this,e,l,q,a,c),f&&1=this.D&&!m[l]?(m[l]=1,r=this.I&&l>q,P(this,g,r?q:l,0,a,c,r?l:q)):n=Math.min(n+1,d-k)}}}this.s||(this.register[a]=1)}return this}; +function P(a,b,c,d,f,h,e){var g=e?a.h:a.map;if(!b[c]||e&&!b[c][e])a.B&&(g=g[d]),e?(b=b[c]||(b[c]=B()),b[e]=1,g=g[e]||(g[e]=B())):b[c]=1,g=g[c]||(g[c]=[]),a.B||(g=g[d]||(g[d]=[])),h&&-1!==g.indexOf(f)||(g[g.length]=f,a.s&&(a=a.register[f]||(a.register[f]=[]),a[a.length]=g))} +u.search=function(a,b,c){E(a)?(c=a,a=c.query):E(b)&&(c=b);var d=[],f=0;if(c){b=c.limit;f=c.offset||0;var h=c.context;var e=c.suggest}if(a){a=this.encode(a);var g=a.length;if(1=this.D&&!c[q])if(this.B||e||this.map[q])k[m++]=q,c[q]=1;else return d;a=k;g=a.length}}if(!g)return d;b||(b=100);h=this.depth&&1=d)))break;if(m){if(h)return ya(k,d,0);b[b.length]=k;return}}return!c&&k}function ya(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function za(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}u.contain=function(a){return!!this.register[a]};u.update=function(a,b){return this.remove(a).add(a,b)}; +u.remove=function(a,b){var c=this.register[a];if(c){if(this.s)for(var d=0,f;db||c)f=f.slice(c,c+b);d&&(f=Ea.call(this,f));return{tag:a,result:f}}}function Ea(a){for(var b=Array(a.length),c=0,d;c=b)return h.concat(l.slice(c,b-f+c));h=h.concat(c? -l.slice(c):l);f+=n;c=0}return h};G["latin:default"]=E; -function I(a,b){if(!(this instanceof I))return new I(a);let c;if(a){var d=a.charset;c=a.lang;"string"===typeof d&&(-1===d.indexOf(":")&&(d+=":default"),d=G[d]);"string"===typeof c&&(c=F[c])}else a={};let e,h,g,f=a.context||{};this.encode=a.encode||d&&d.encode||E;this.register=b||y();e=a.resolution||9;h=a.threshold||0;h>=e&&(h=e-1);this.i=e;this.s=h;this.F=b=d&&d.G||a.tokenize||"strict";this.m="strict"===b&&f.depth;this.v=u(f.bidirectional,!0);this.g=g="memory"===a.optimize;this.C=u(a.fastupdate,!0); -this.h=a.minlength||1;this.j=g?v(e-h):y();e=f.resolution||e;h=f.threshold||h;h>=e&&(h=e-1);this.l=e;this.D=h;this.B=g?v(e-h):y();this.u=d&&d.u||a.rtl;this.o=(b=a.matcher||c&&c.o)&&B(b,!1);this.A=(b=a.stemmer||c&&c.A)&&B(b,!0);if(a=b=a.filter||c&&c.filter){a=b;d=y();for(let k=0,l=a.length;k=this.h&&(n||!q[p])){var h=Math.min(this.i/d*m|0,m);if(hf;l--)g=p.substring(f,l),g.length>=this.h&&J(this,q,g,k,a,c)}break}case "reverse":if(2< -e){for(f=e-1;0=this.h&&J(this,q,g,h,a,c);g=""}case "forward":if(1=this.h&&J(this,q,g,h,a,c);break;default:if(J(this,q,p,h,a,c),n&&1=this.h&&!h[p]){if(h[p]=1,l=Math.min((this.l-f)/d*m+k|0,m+(k-1)),lg;J(this,t,x?g:p,l,a,c,x?p:g)}}else f=Math.min(f+1,d-m)}}}}this.C||(this.register[a]=1)}return this}; -function J(a,b,c,d,e,h,g){let f=g?a.B:a.j;if(!b[c]||g&&!b[c][g])a.g&&(f=f[d]),g?(b=b[c]||(b[c]=y()),b[g]=1,f=f[g]||(f[g]=y())):b[c]=1,f=f[c]||(f[c]=[]),a.g||(f=f[d]||(f[d]=[])),h&&-1!==f.indexOf(e)||(f[f.length]=e,a.C&&(a=a.register[e]||(a.register[e]=[]),a[a.length]=f))} -I.prototype.search=function(a,b,c){"object"===typeof a?(c=a,a=c.query):"object"===typeof b&&(c=b);let d=[],e;var h=this.s;let g,f=0;if(c){b=c.limit;f=c.offset||0;h=u(c.threshold,h);var k=c.context;g=!1}if(a&&(a=this.encode(a),e=a.length,1=this.h&&!c[t])if(this.g||g||this.j[t])l[q++]=t,c[t]=1;else return d;a=l;e=a.length}if(!e)return d;b||(b=100);c=this.i-h;h=this.l-h;k=this.m&&1=e)));q++);if(r){if(g)return L(l,e,0);b[b.length]=l;return}}return!c&&l}function L(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} -function M(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}I.prototype.contain=function(a){return!!this.register[a]};I.prototype.update=function(a,b){return this.remove(a).add(a,b)};I.prototype.remove=function(a,b){const c=this.register[a];if(c){if(this.C)for(let d=0,e;d=this.h&&(m||!q[k])){var h=Math.min(n/d*p|0,p),g="";switch(this.C){case "full":if(3e;t--)g=k.substring(e,t),g.length>=this.h&&L(this,q,g,l,a,b)}break}case "reverse":if(2=this.h&&L(this,q,g,h,a,b);g=""}case "forward":if(1=this.h&&L(this,q,g,h,a,b);break;default:if(L(this,q,k,h,a,b),m&&1=this.h&&!f[k]?(f[k]=1,l=this.l&&k>h,L(this,r,l?h:k,0,a,b,l?k:h)):g=Math.min(g+1,d-p)}}}this.s||(this.register[a]=1)}return this}; +function L(a,c,b,d,f,h,g){let e=g?a.m:a.i;if(!c[b]||g&&!c[b][g])a.g&&(e=e[d]),g?(c=c[b]||(c[b]=z()),c[g]=1,e=e[g]||(e[g]=z())):c[b]=1,e=e[b]||(e[b]=[]),a.g||(e=e[d]||(e[d]=[])),h&&-1!==e.indexOf(f)||(e[e.length]=f,a.s&&(a=a.register[f]||(a.register[f]=[]),a[a.length]=e))} +K.prototype.search=function(a,c,b){"object"===typeof a?(b=a,a=b.query):"object"===typeof c&&(b=c);let d=[],f;let h,g=0;if(b){c=b.limit;g=b.offset||0;var e=b.context;h=!1}if(a&&(a=this.encode(a),f=a.length,1=this.h&&!b[r])if(this.g||h||this.i[r])l[q++]=r,b[r]=1;else return d;a=l;f=a.length}if(!f)return d;c||(c=100);e=this.j&&1=d)))break;if(n){if(h)return O(l,d,0);c[c.length]=l;return}}return!b&&l}function O(a,c,b){a=1===a.length?a[0]:[].concat.apply([],a);return b||a.length>c?a.slice(b,b+c):a} +function P(a,c,b,d){b?(d=d&&c>b,a=(a=a[d?c:b])&&a[d?b:c]):a=a[c];return a}K.prototype.contain=function(a){return!!this.register[a]};K.prototype.update=function(a,c){return this.remove(a).add(a,c)};K.prototype.remove=function(a,c){const b=this.register[a];if(b){if(this.s)for(let d=0,f;d Entries from an extern store are not being managed/changed automatically by FlexSearch. When removing items from the index, the corresponding data item from the extern dataset stays untouched. Please consider, using the method `index.set(id, data)` will change extern stores also. - -When you didn't use the data anywhere in your application (just for searching) then it is better to use an internal store and just select fields you need in the results, which costs you less memory. - -## WebWorker +## Worker Parallelism (Browser + Node.js) The whole worker implementation has changed by also keeping Node.js support in mind. The good news is worker will also get supported by Node.js by the library. @@ -1217,7 +1182,21 @@ index.searchAsync(query).then(callback); index.searchAsync(query).then(callback); ``` -When using `await` you can prioritize the order ("first task completed") and solve requests one by one and process sub-tasks in parallel: +Or when you have just one callback when all requests are done, simply use `Promise.all()` which also prioritize "all tasks completed": + +```js +Promise.all([ + + index.searchAsync(query).then(callback), + index.searchAsync(query).then(callback), + index.searchAsync(query).then(callback) + +]).then(callback); +``` + +Inside the callback of `Promise.all()` you will also get an array of results as the first parameter respectively for each query you put into. + +When using `await` you can prioritize the order (prioritize "first task completed") and solve requests one by one and just process the sub-tasks in parallel: ```js await index.searchAsync(query); @@ -1545,7 +1524,6 @@ index = new Index({ tokenize: "strict", optimize: "memory", resolution: 1, - threshold: 0, minlength: 3, fastupdate: false, context: false @@ -1555,28 +1533,25 @@ index = new Index({ ### Compare Impact of Memory Allocation by default a lexical index is very small:
-`depth: 0, bidirectional: 0, resolution: 3, threshold: 0, minlength: 0` => 2.1 Mb +`depth: 0, bidirectional: 0, resolution: 3, minlength: 0` => 2.1 Mb a higher resolution will increase the memory allocation:
-`depth: 0, bidirectional: 0, resolution: 9, threshold: 0, minlength: 0` => 2.9 Mb +`depth: 0, bidirectional: 0, resolution: 9, minlength: 0` => 2.9 Mb using the contextual index will increase the memory allocation:
-`depth: 1, bidirectional: 0, resolution: 9, threshold: 0, minlength: 0` => 12.5 Mb +`depth: 1, bidirectional: 0, resolution: 9, minlength: 0` => 12.5 Mb a higher contextual depth will increase the memory allocation:
-`depth: 2, bidirectional: 0, resolution: 9, threshold: 0, minlength: 0` => 21.5 Mb +`depth: 2, bidirectional: 0, resolution: 9, minlength: 0` => 21.5 Mb a higher minlength will decrease memory allocation:
-`depth: 2, bidirectional: 0, resolution: 9, threshold: 0, minlength: 3` => 19.0 Mb +`depth: 2, bidirectional: 0, resolution: 9, minlength: 3` => 19.0 Mb using bidirectional will decrease memory allocation:
-`depth: 2, bidirectional: 1, resolution: 9, threshold: 0, minlength: 3` => 17.9 Mb - -a higher threshold will decrease memory allocation:
-`depth: 2, bidirectional: 1, resolution: 9, threshold: 5, minlength: 3` => 5.8 Mb +`depth: 2, bidirectional: 1, resolution: 9, minlength: 3` => 17.9 Mb enable the option "fastupdate" will increase memory allocation:
-`depth: 2, bidirectional: 1, resolution: 9, threshold: 5, minlength: 3` => 6.3 Mb +`depth: 2, bidirectional: 1, resolution: 9, minlength: 3` => 6.3 Mb ### Full Comparison Table @@ -1608,14 +1583,6 @@ FlexSearch provides you many parameters you can use to adjust the optimal balanc +2 (per level) - - threshold - -4 (per level) - -3 (per level) - +2 (per level) - 0 - - depth +4 (per level) diff --git a/doc/contextual-index.svg b/doc/contextual-index.svg index cae6e16..983e99b 100644 --- a/doc/contextual-index.svg +++ b/doc/contextual-index.svg @@ -1,2 +1,2 @@ -
Word 4
Word 4
Contextual Index
[Not supported by viewer]
Context of Relevance
Context of Relevance
Query
Query
2. contextual score
[Not supported by viewer]
1. partial score
1. partial score
context limit (depth)
[Not supported by viewer]
3. document score
[Not supported by viewer]
"Model of Contextual-based Scoring"
Copyright 2018 Thomas Wilkerling
Nextapps GmbH
[Not supported by viewer]
Word 2
Word 2
Word 3
Word 3
Word 5
Word 5
Word 6
Word 6
Word 1
Word 1
Word 7
Word 7
...
...
...
...
+
Word 4
Word 4
Contextual Index
[Not supported by viewer]
Context of Relevance
Context of Relevance
Query
Query
2. contextual score
[Not supported by viewer]
1. partial score
1. partial score
context limit (depth)
[Not supported by viewer]
3. document score
[Not supported by viewer]
"Model of Contextual-based Scoring"
Copyright 2018 Thomas Wilkerling
Nextapps GmbH
[Not supported by viewer]
Word 2
Word 2
Word 3
Word 3
Word 5
Word 5
Word 6
Word 6
Word 1
Word 1
Word 7
Word 7
...
...
...
...
diff --git a/src/async.js b/src/async.js index 5a147eb..31f1c08 100644 --- a/src/async.js +++ b/src/async.js @@ -1,5 +1,5 @@ import { IndexInterface, DocumentInterface } from "./type.js"; -import { promise as Promise } from "./polyfill.js"; +//import { promise as Promise } from "./polyfill.js"; import { is_function, is_object, is_string } from "./common.js"; export default function(prototype){ diff --git a/src/document.js b/src/document.js index 8cb4bb4..98b43d5 100644 --- a/src/document.js +++ b/src/document.js @@ -52,9 +52,8 @@ function Document(options){ if(SUPPORT_STORE){ - this.extern = !!(opt = document["extern"]); - this.storetree = !this.extern && (opt = document["store"]) && (opt !== true) && []; - this.store = opt && (this.extern ? opt : create_object()); + this.storetree = (opt = document["store"]) && (opt !== true) && []; + this.store = opt && create_object(); } if(SUPPORT_TAGS){ @@ -84,6 +83,7 @@ function Document(options){ this.async = false; } + /** @export */ this.index = parse_descriptor.call(this, options, document); } @@ -97,17 +97,11 @@ function parse_descriptor(options, document){ const index = create_object(); let field = document["index"] || document["field"] || document; - //let field_options; if(is_string(field)){ field = [field]; } - // else if(!is_array(field)){ - // - // field_options = field; - // field = get_keys(field); - // } for(let i = 0, key, opt; i < field.length; i++){ @@ -118,10 +112,6 @@ function parse_descriptor(options, document){ opt = key; key = key["field"]; } - // else if(field_options){ - // - // opt = field_options[key]; - // } opt = is_object(opt) ? Object.assign({}, options, opt) : options; @@ -363,7 +353,7 @@ Document.prototype.add = function(id, content, _append){ } } - if(SUPPORT_STORE && this.store && !this.extern){ + if(SUPPORT_STORE && this.store){ let store; @@ -454,7 +444,7 @@ Document.prototype.remove = function(id){ } } - if(SUPPORT_STORE && this.store && !this.extern){ + if(SUPPORT_STORE && this.store){ delete this.store[id]; } @@ -488,7 +478,7 @@ Document.prototype.search = function(query, limit, options, _resolve){ let result = [], result_field = []; let pluck, enrich; - let field, field_options, tag, bool, offset, count = 0; + let field, tag, bool, offset, count = 0; if(options){ @@ -497,11 +487,6 @@ Document.prototype.search = function(query, limit, options, _resolve){ field = options; options = null; } - // else if(is_string(options)){ - // - // field = [options]; - // options = null; - // } else{ pluck = options["pluck"]; @@ -539,22 +524,14 @@ Document.prototype.search = function(query, limit, options, _resolve){ } } - //if(field){ + if(is_string(field)){ - if(is_string(field)){ + field = [field]; + } + else if(!is_array(field)){ - field = [field]; - } - else if(!is_array(field)){ - - field = null; - } - // else if(!is_array(field)){ - // - // field_options = field; - // field = get_keys(field); - // } - //} + field = null; + } } } @@ -576,10 +553,6 @@ Document.prototype.search = function(query, limit, options, _resolve){ opt = key; key = key["field"]; } - // else if(field_options){ - // - // opt = field_options[key]; - // } if(promises){ diff --git a/src/index.js b/src/index.js index 4ee3baf..16c0dff 100644 --- a/src/index.js +++ b/src/index.js @@ -76,22 +76,12 @@ function Index(options, _register){ options = {}; } - let resolution, threshold, optimize, context = options["context"] || {}; + let resolution, optimize, context = options["context"] || {}; /** @export */ this.encode = options["encode"] || (charset && charset.encode) || default_encoder; this.register = _register || create_object(); - - resolution = options["resolution"] || 9; - threshold = options["threshold"] || 0; - - if(threshold >= resolution){ - - threshold = resolution - 1; - } - - this.resolution = resolution; - this.threshold = threshold; + this.resolution = resolution = options["resolution"] || 9; this.tokenizer = tmp = (charset && charset.tokenize) || options["tokenize"] || "strict"; this.depth = (tmp === "strict") && context["depth"]; this.bidirectional = parse_option(context["bidirectional"], true); @@ -101,19 +91,9 @@ function Index(options, _register){ // when not using the memory strategy the score array should not pre-allocated to its full length - this.map = optimize ? create_object_array(resolution - threshold) : create_object(); - - resolution = context["resolution"] || resolution; - threshold = context["threshold"] || threshold; - - if(threshold >= resolution){ - - threshold = resolution - 1; - } - - this.resolution_ctx = resolution; - this.threshold_ctx = threshold; - this.ctx = optimize ? create_object_array(resolution - threshold) : create_object(); + this.map = optimize ? create_object_array(resolution) : create_object(); + this.resolution_ctx = resolution = context["resolution"] || 1; + this.ctx = optimize ? create_object_array(resolution) : create_object(); this.rtl = (charset && charset.rtl) || options["rtl"]; this.matcher = (tmp = options["matcher"] || (lang && lang.matcher)) && init_stemmer_or_matcher(tmp, false); this.stemmer = (tmp = options["stemmer"] || (lang && lang.stemmer)) && init_stemmer_or_matcher(tmp, true); @@ -161,7 +141,7 @@ Index.prototype.add = function(id, content, _append, _skip_update){ if(length){ const depth = this.depth; - const resolution = this.resolution - this.threshold; + const resolution = this.resolution; const dupes = create_object(); // check context dupes to skip all contextual redundancy in the whole document const dupes_ctx = create_object(); @@ -174,9 +154,9 @@ Index.prototype.add = function(id, content, _append, _skip_update){ // skip dupes will break the context chain if(term && (term_length >= this.minlength) && (depth || !dupes[term])){ - const score = Math.min((this.resolution / length * i) | 0, i); + const score = Math.min((resolution / length * i) | 0, i); - if(score < resolution){ + //if(score < resolution){ let token = ""; @@ -188,9 +168,9 @@ Index.prototype.add = function(id, content, _append, _skip_update){ for(let x = 0; x < term_length; x++){ - const partial_score = x ? Math.min((score / 2 + this.resolution / term_length * x / 2) | 0, score + x) : score; + const partial_score = x ? Math.min((score / 2 + resolution / term_length * x / 2) | 0, score + x) : score; - if(partial_score < resolution){ + //if(partial_score < resolution){ for(let y = term_length; y > x; y--){ @@ -201,7 +181,7 @@ Index.prototype.add = function(id, content, _append, _skip_update){ this.push_index(dupes, token, partial_score, id, _append); } } - } + //} } break; @@ -256,7 +236,7 @@ Index.prototype.add = function(id, content, _append, _skip_update){ if((length > 1) && (i < (length - 1))){ - const resolution = this.resolution_ctx - this.threshold_ctx; + const resolution = this.resolution_ctx; // check inner dupes to skip repeating words in the current context const dupes_inner = create_object(); const keyword = term; @@ -272,14 +252,17 @@ Index.prototype.add = function(id, content, _append, _skip_update){ dupes_inner[term] = 1; - const context_score = Math.min(((this.resolution_ctx - size /*+ 1*/) / length * i + x) | 0, i + (x - 1)); + const context_score = 0; - if(context_score < resolution){ + // const context_score = Math.min(((resolution - size /*+ 1*/) / length * i + x) | 0, i + (x - 1)); + // + // // TODO: this check is not required when calculated properly + // if((context_score >= 0) && (context_score < resolution)){ const swap = this.bidirectional && (term > keyword); this.push_index(dupes_ctx, swap ? keyword : term, context_score, id, _append, swap ? term : keyword); - } + //} } else{ @@ -289,7 +272,7 @@ Index.prototype.add = function(id, content, _append, _skip_update){ } } } - } + //} } } @@ -376,13 +359,12 @@ Index.prototype.search = function(query, limit, options){ let result = []; let length; - let threshold = this.threshold, context, suggest, offset = 0; + let context, suggest, offset = 0; if(options){ limit = options["limit"]; offset = options["offset"] || 0; - threshold = parse_option(options["threshold"], threshold); context = options["context"]; suggest = SUPPORT_SUGGESTION && options["suggest"]; } @@ -433,8 +415,6 @@ Index.prototype.search = function(query, limit, options){ limit || (limit = 100); - const resolution = this.resolution - threshold; - const resolution_ctx = this.resolution_ctx - threshold; let depth = this.depth && (length > 1) && (context !== false); let index = 0, keyword; @@ -457,7 +437,7 @@ Index.prototype.search = function(query, limit, options){ if(depth){ - arr = this.add_result(result, suggest, resolution_ctx, limit, offset, length === 2, term, keyword); + arr = this.add_result(result, suggest, limit, offset, length === 2, term, keyword); // when suggestion enabled just forward keyword if term was found // as long as the result is empty forward the pointer also @@ -469,7 +449,7 @@ Index.prototype.search = function(query, limit, options){ } else{ - arr = this.add_result(result, suggest, resolution, limit, offset, length === 1, term); + arr = this.add_result(result, suggest, limit, offset, length === 1, term); } if(arr){ @@ -517,7 +497,6 @@ Index.prototype.search = function(query, limit, options){ * @private * @param {Array} result * @param {Array} suggest - * @param {number} resolution * @param {number} limit * @param {number} offset * @param {boolean} single_term @@ -526,7 +505,7 @@ Index.prototype.search = function(query, limit, options){ * @return {Array>|boolean|undefined} */ -Index.prototype.add_result = function(result, suggest, resolution, limit, offset, single_term, term, keyword){ +Index.prototype.add_result = function(result, suggest, limit, offset, single_term, term, keyword){ let word_arr = []; let arr = keyword ? this.ctx : this.map; @@ -539,53 +518,57 @@ Index.prototype.add_result = function(result, suggest, resolution, limit, offset if(arr){ let count = 0; - const arr_len = Math.min(arr.length, resolution); + const arr_len = Math.min(arr.length, keyword ? this.resolution_ctx : this.resolution); + // relevance: for(let x = 0, size = 0, tmp, len; x < arr_len; x++){ tmp = arr[x]; - if(this.optimize){ - - tmp = get_array(tmp, term, keyword, this.bidirectional); - } - - if(tmp && single_term){ - - len = tmp.length; - - if(len <= offset){ - - offset -= len; - tmp = null; - } - else{ - - if(offset){ - - tmp = tmp.slice(offset); - offset = 0; - } - } - } - if(tmp){ - // keep score (sparse array): - //word_arr[x] = tmp; + if(this.optimize){ - // simplified score order: - word_arr[count++] = tmp; + tmp = get_array(tmp, term, keyword, this.bidirectional); + } - if(single_term){ + if(offset){ - size += tmp.length; + if(tmp && single_term){ - if(size >= limit){ + len = tmp.length; - // fast path optimization + if(len <= offset){ - break; + offset -= len; + tmp = null; + } + else{ + + tmp = tmp.slice(offset); + offset = 0; + } + } + } + + if(tmp){ + + // keep score (sparse array): + //word_arr[x] = tmp; + + // simplified score order: + word_arr[count++] = tmp; + + if(single_term){ + + size += tmp.length; + + if(size >= limit){ + + // fast path optimization + + break; + } } } } @@ -679,11 +662,11 @@ Index.prototype.remove = function(id, _skip_deletion){ } else{ - remove_index(this.map, id, this.resolution - this.threshold, this.optimize); + remove_index(this.map, id, this.resolution, this.optimize); if(this.depth){ - remove_index(this.ctx, id, this.resolution_ctx - this.threshold_ctx, this.optimize); + remove_index(this.ctx, id, this.resolution_ctx, this.optimize); } } diff --git a/src/intersect.js b/src/intersect.js index 09054f9..be42824 100644 --- a/src/intersect.js +++ b/src/intersect.js @@ -1,6 +1,7 @@ import { create_object, concat } from "./common.js"; /** + * Implementation based on Array.indexOf() * @param arrays * @param limit * @param offset @@ -12,124 +13,177 @@ export function intersect(arrays, limit, offset, suggest) { const length = arrays.length; let result = []; - - // arrays.sort(function(a, b){ - // - // return a.length - b.length; - // }); - let check; - let count = 0; + + // determine shortest array and collect results + // from the sparse relevance arrays + + let smallest_size; + let smallest_arr; + let smallest_index; + + for(let x = 0; x < length; x++){ + + const arr = arrays[x]; + const len = arr.length; + + let size = 0; + + for(let y = 0, tmp; y < len; y++){ + + tmp = arr[y]; + + if(tmp){ + + size += tmp.length; + } + } + + if(!smallest_size || (size < smallest_size)){ + + smallest_size = size; + smallest_arr = arr; + smallest_index = x; + } + } + + smallest_arr = smallest_arr.length === 1 ? + + smallest_arr[0] + : + concat(smallest_arr); if(suggest){ - suggest = []; + suggest = [smallest_arr]; + check = create_object(); } - // terms in reversed order! + let size = 0; + let steps = 0; + + // TODO: the first word should be processed in the last round? + + // process terms in reversed order often results in better performance + // the outer loop must be the words array, + // using the smallest array here disables the "fast fail" optimization + for(let x = length - 1; x >= 0; x--){ - const word_arr = arrays[x]; - const word_arr_len = word_arr.length; - const new_check = create_object(); + if(x !== smallest_index){ - let found = !check; + steps++; - // but relevance in forward order - for(let y = 0; y < word_arr_len; y++){ + const word_arr = arrays[x]; + const word_arr_len = word_arr.length; + const new_arr = []; - //const arr = [].concat.apply([], word_arr); - const arr = word_arr[y]; - const arr_len = arr.length; + let count = 0; - if(arr_len){ + for(let z = 0, id; z < smallest_arr.length; z++){ - // ids - for(let z = 0, count_suggest = 0, id; z < arr_len; z++){ + id = smallest_arr[z]; - id = arr[z]; + let found; - if(!check){ + // process relevance in forward order (direction is + // important for the "fill" during the last round) - new_check[id] = 1; - } - else if(check[id]){ + for(let y = 0; y < word_arr_len; y++){ - if(!x){ + const arr = word_arr[y]; - if(offset){ + if(arr.length){ - offset--; - } - else{ + found = arr.indexOf(id) !== -1; - result[count++] = id; + if(found){ - if(count === limit){ + // check if in last round - // fast path "end reached" + if(steps === length - 1){ - return result; + if(offset){ + + offset--; + } + else{ + + result[size++] = id; + + if(size === limit){ + + // fast path "end reached" + + return result; + } + } + + if(suggest){ + + check[id] = 1; } } + + break; } - else{ - - if(suggest && (count_suggest < limit)){ - - const tmp = suggest[y] || (suggest[y] = []); - - tmp[count_suggest++] = id; - } - - new_check[id] = 1; - } - - found = true; } } + + if(found){ + + new_arr[count++] = id; + } } + + if(suggest){ + + suggest[steps] = new_arr; + } + else if(!count){ + + return []; + } + + smallest_arr = new_arr; } - - if(!found && !suggest){ - - return []; - } - - check = new_check; } if(suggest){ - for(let i = suggest.length - 1, res, len; i >= 0; i--){ + // has to iterate in reverse direction - res = suggest[i]; - len = res && res.length; + for(let x = suggest.length - 1, arr, len; x >= 0; x--){ - if(len && offset){ - - if(len <= offset){ - - offset -= len; - len = 0; - } - else{ - - len -= offset; - } - } + arr = suggest[x]; + len = arr && arr.length; if(len){ - if(count + len >= limit){ + for(let y = 0, id; y < len; y++){ - return result.concat(res.slice(offset, limit - count + offset)); - } - else{ + id = arr[y]; - result = result.concat(offset ? res.slice(offset) : res); - count += len; - offset = 0; + if(!check[id]){ + + check[id] = 1; + + if(offset){ + + offset--; + } + else{ + + result[size++] = id; + + if(size === limit){ + + // fast path "end reached" + + return result; + } + } + } } } } @@ -138,6 +192,145 @@ export function intersect(arrays, limit, offset, suggest) { return result; } +/** + * Implementation based on Object[key] + * @param arrays + * @param limit + * @param offset + * @param {boolean|Array=} suggest + * @returns {Array} + */ + +// export function intersect(arrays, limit, offset, suggest) { +// +// const length = arrays.length; +// let result = []; +// +// // arrays.sort(function(a, b){ +// // +// // return a.length - b.length; +// // }); +// +// let check; +// let count = 0; +// +// if(suggest){ +// +// suggest = []; +// } +// +// // terms in reversed order! +// for(let x = length - 1; x >= 0; x--){ +// +// const word_arr = arrays[x]; +// const word_arr_len = word_arr.length; +// const new_check = create_object(); +// +// let found = !check; +// +// // relevance in forward order +// for(let y = 0, count_suggest = 0; y < word_arr_len; y++){ +// +// //const arr = [].concat.apply([], word_arr); +// const arr = word_arr[y]; +// const arr_len = arr.length; +// +// if(arr_len){ +// +// // ids +// for(let z = 0, id; z < arr_len; z++){ +// +// id = arr[z]; +// +// if(!check){ +// +// new_check[id] = 1; +// } +// else if(check[id]){ +// +// if(!x){ +// +// if(offset){ +// +// offset--; +// } +// else{ +// +// result[count++] = id; +// +// if(count === limit){ +// +// // fast path "end reached" +// +// return result; +// } +// } +// } +// else{ +// +// if(suggest && (count_suggest < limit)){ +// +// const tmp = suggest[y] || (suggest[y] = []); +// tmp[tmp.length] = id; +// count_suggest++; +// } +// +// new_check[id] = 1; +// } +// +// found = true; +// } +// } +// } +// } +// +// if(!found && !suggest){ +// +// return []; +// } +// +// check = new_check; +// } +// +// if(suggest){ +// +// for(let i = suggest.length - 1, res, len; i >= 0; i--){ +// +// res = suggest[i]; +// len = res && res.length; +// +// if(len && offset){ +// +// if(len <= offset){ +// +// offset -= len; +// len = 0; +// } +// else{ +// +// len -= offset; +// } +// } +// +// if(len){ +// +// if(count + len >= limit){ +// +// return result.concat(res.slice(offset, limit - count + offset)); +// } +// else{ +// +// result = result.concat(offset ? res.slice(offset) : res); +// count += len; +// offset = 0; +// } +// } +// } +// } +// +// return result; +// } + /** * @param mandatory * @param arrays diff --git a/src/worker/index.js b/src/worker/index.js index 1ef7c73..b86766e 100644 --- a/src/worker/index.js +++ b/src/worker/index.js @@ -1,4 +1,4 @@ -import { promise as Promise } from "../polyfill.js"; +//import { promise as Promise } from "../polyfill.js"; import { create_object, is_function, is_object, is_string } from "../common.js"; import handler from "./handler.js";