diff --git a/README.md b/README.md index d41d8b6..293d77d 100644 --- a/README.md +++ b/README.md @@ -70,13 +70,31 @@ All Features: - Web-Worker Sharding (not available in Node.js) + Presets x x - + + + Async Processing + + x + x + - + + + + + Web-Worker Sharding (not available in Node.js) + + x + - + - + + Contextual Indexes @@ -115,10 +133,10 @@ All Features: - Auto-Balanced Cache by Popularity + Auto-Balanced Cache by Popularity x - x + - - @@ -127,22 +145,13 @@ All Features: Suggestions (Results) x - x + - - - Asynchronous Processing & Concurrency Control - - x - x - - - - - - - Phonetic Mathching + Phonetic Matching x x @@ -161,7 +170,7 @@ All Features: File Size (gzip) 6.7 kb 4.5 kb - 1.9 kb + 2.1 kb @@ -188,9 +197,9 @@ __Query Test: "Gulliver's Travels"__ 1 FlexSearch - 0.3.0 - 2.9 kb - 316336 + 0.3.1 + 2.1 kb + 327771 @@ -198,7 +207,7 @@ __Query Test: "Gulliver's Travels"__ Wade 0.3.3 1.6 kb - 1524 + 1587 @@ -206,7 +215,7 @@ __Query Test: "Gulliver's Travels"__ JS Search 1.4.2 3.8 kb - 739 + 771 @@ -214,7 +223,7 @@ __Query Test: "Gulliver's Travels"__ JSii 1.0 3.9 kb - 544 + 584 @@ -222,7 +231,7 @@ __Query Test: "Gulliver's Travels"__ Lunr.js 2.3.5 8.8 kb - 310 + 322 @@ -230,7 +239,7 @@ __Query Test: "Gulliver's Travels"__ Elasticlunr.js 0.9.6 5.6 kb - 286 + 319 @@ -246,7 +255,7 @@ __Query Test: "Gulliver's Travels"__ bm25 0.2 3.5 kb - 72 + 107 @@ -272,7 +281,7 @@ __Memory Test: "Gulliver's Travels"__ 1 FlexSearch - 0.3.0 + 0.3.1 1.33 Mb 20.31 kb @@ -594,6 +603,27 @@ index.search("John", function(result){ }); ``` +Perform queries asynchronously (Promise-based): + +> Make sure the option "async" is enabled on this instance + +```js +index.search("John").then(function(result){ + + // array of results +}); +``` + +Alternatively ES6: + +```js +async function search(query){ + return await index.search(query); +} + +const result = search("John"); +``` + Pass custom options for each query: ```js @@ -905,6 +935,7 @@ var index = new FlexSearch({ }); ``` + #### Enable Auto-Balanced Cache Create index and just set a limit of cache entries: @@ -1504,7 +1535,17 @@ __Supported Build Flags__ Values - SUPPORT_DEBUG + DEBUG + true, false + + + + PROFILER + true, false + + + + SUPPORT_ENCODER (built-in encoders) true, false @@ -1524,7 +1565,7 @@ __Supported Build Flags__ - SUPPORT_BUILTINS (built-in encoders) + SUPPORT_PRESETS true, false diff --git a/flexsearch.compact.js b/flexsearch.compact.js index 3e91570..76cf347 100644 --- a/flexsearch.compact.js +++ b/flexsearch.compact.js @@ -1,24 +1,31 @@ /* - FlexSearch v0.3.0 + FlexSearch v0.3.1 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(m,x,c){var r;(r=c.define)&&r.amd?r([],function(){return x}):(r=c.modules)?r[m.toLowerCase()]=x:"object"===typeof exports?module.exports=x:c[m]=x})("FlexSearch",function(){function m(b){"string"===typeof b&&(b=D[b]);b||(b=v);this.id=b.id||J++;this.init(b);x(this,"index",function(){return this.a});x(this,"length",function(){return Object.keys(this.a).length})}function x(b,a,d){Object.defineProperty(b,a,{get:d})}function c(b){return new RegExp(b,"g")}function r(b,a,d){if("undefined"=== -typeof d){for(d=0;d=c&&(b=b[g+.5>>0],b=b[d]||(b[d]=[]),b[b.length]=n);return g}function A(b,a){if(b)for(var d=Object.keys(b),n=0,g=d.length;n=(8=(8b?1:b?-1:0}function L(b,a){b=b.length-a.length;return 0>b?-1:b?1:0}function F(b){for(var a=Array(b),d=0;dl;r--)q=u.substring(l,r),z(k,c,q,b,m,t,g);break;default:if(p=z(k,c,u,b,1,t,g),e&&1=g)for(p=c._ctx[u]||(c._ctx[u]={}),u=this.c[u]||(this.c[u]=F(10)),t=h-e,q=h+e+1,0>t&&(t=0),q>f&&(q=f);ta;a++)A(this.i[a],b);this.depth&&A(this.c,b);delete this.a[b];this.h=!1}return this};m.prototype.search=function(b,a,d){var c=[];if("object"===typeof b){d=b.callback||a;a=b.limit;var g=b.threshold;b=b.query}g||(g=this.threshold||0);"function"===typeof a?(d=a,a=1E3):a||0===a||(a=1E3);if(d)d(this.search(b,a));else{if(!b||"string"!==typeof b)return c;d=b;if(this.cache)if(this.h){var e=this.b.get(b);if(e)return e}else this.b.clear(),this.h=!0;d=this.encode(d); -if(!d.length)return c;e=this.mode;e="function"===typeof e?e(d):"ngram"===e?E(d):d.split(G);var k=e.length,f=!0;d=[];var h={};if(1=g;v--)m=(u?t[p]:this.i)[v],m[l]&&(w[x++]=m[l],r=!0);if(r)d[d.length]=1a&&(c=c.slice(0,a)));this.cache&&this.b.set(b,c);return c}};m.prototype.clear= -function(){this.destroy();return this.init()};m.prototype.destroy=function(){this.cache&&(this.b.clear(),this.b=null);this.filter=this.stemmer=this.i=this.c=this.a=null;return this};var y={icase:function(b){return b.toLowerCase()},simple:function(){var b=[c("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"),"a",c("[\u00e8\u00e9\u00ea\u00eb]"),"e",c("[\u00ec\u00ed\u00ee\u00ef]"),"i",c("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"),"o",c("[\u00f9\u00fa\u00fb\u00fc\u0171]"),"u",c("[\u00fd\u0177\u00ff]"),"y",c("\u00f1"), -"n",c("\u00e7"),"c",c("\u00df"),"s",c(" & ")," and ",c("[-/]")," ",c("[^a-z0-9 ]"),"",c("\\s\\s+")," "];return function(a){a=r(a.toLowerCase(),b);return" "!==a?a:""}}(),advanced:function(){var b=[c("ae"),"a",c("ai"),"ei",c("ay"),"ei",c("ey"),"ei",c("oe"),"o",c("ue"),"u",c("ie"),"i",c("sz"),"s",c("zs"),"s",c("sh"),"s",c("ck"),"k",c("cc"),"k",c("dt"),"t",c("ph"),"f",c("pf"),"f",c("ou"),"o",c("uo"),"u"];return function(a,d){if(!a)return a;a=this.simple(a);2e;c--)f=k[c-1],k[c]=f,g[f]=c;k[e]=a;g[a]=e}}}return b};return b}();return m}(!1),this); +'use strict';function J(d){var c=0;return function(){return c=l&&(b=b[d+.5>>0],b=b[a]||(b[a]=[]),b[b.length]=c);return d}function w(b,e){if(b)for(var a=Object.keys(b),c=0,d=a.length;c=(8=(8b? +1:b?-1:0}function z(b,e){b=b.length-e.length;return 0>b?-1:b?1:0}function V(b,e,a){var c=[],d=[],f=b.length;if(1e&&(c=c.slice(0,e)));return c}function F(b){return"string"===typeof b}function A(b){return"function"===typeof b}function v(b){return"undefined"===typeof b}function H(b){b.j||(b.j=N(function(){b.j=0;var a=b.async;a&&(b.async=!1);if(b.b.length){for(var c=Date.now(),d;(d=b.b.shift())||0===d;){var f=b.c[d];switch(f[0]){case G.add:b.add(f[1],f[2]);break;case G.remove:b.remove(f[1])}delete b.c[d];if(100r;u--)n=q.substring(r,u),g(l,e,n,b,v,m,d);break;default:if(k=g(l,e,q,b,1,m,d),f&&1=d)for(k=e._ctx[q]||(e._ctx[q]={}),q=this.f[q]||(this.f[q]=E(10)),m=h-f,n=h+f+1,0>m&&(m=0),n>t&&(n=t);mb;b++)w(this.h[b],a);this.depth&&w(this.f,a);delete this.a[a]}return this};d.prototype.search=function(a,c,d,f){var b=a,e=[];if("object"===typeof a){(d=a.callback||c)&&(b.callback=null);c=a.limit;var g=a.threshold;a=a.query}g||(g=this.threshold||0);A(c)?(d=c,c=1E3):c||0===c||(c=1E3);if(d){var t=this;N(function(){d(t.search(b, +c,null,!0));t=null},1,"search-"+this.id)}else{if(!f&&this.async){var h=this;return new Promise(function(a){a(h.search(b,c,null,!0));h=null})}if(!a||!F(a))return e;b=a;b=this.encode(b);if(!b.length)return e;a=this.mode;a=A(a)?a(b):"ngram"===a?p(b):b.split(O);f=a.length;var q=!0,k=[],m={};if(1=g;z--)if(x=(n?v[r]:this.h)[z], +x=x[w])y[B++]=x,M=!0;if(M)k[k.length]=1} */ - filter[lang] = languagePack["filter"]; + filter[lang] = language_pack["filter"]; /** * @type {Object} */ - stemmer[lang] = languagePack["stemmer"]; + stemmer[lang] = language_pack["stemmer"]; return this; }; /** - * @param {!string} name - * @param {?string} value + * @param {string} name + * @param {string} value * @returns {string} * @export */ FlexSearch.encode = function(name, value){ - // if(index_blacklist[name]){ - // - // return value; - // } - // else{ + if(index_blacklist[name]){ + + return value; + } + else{ return global_encoder[name](value); - //} + } }; /** @@ -279,7 +278,7 @@ FlexSearch.prototype.init = function(options){ - /** @type {Array} */ + /** @type {Array} @private */ this._matcher = []; options || (options = defaults); @@ -287,6 +286,11 @@ let custom = /** @type {?string} */ (options["profile"]); const profile = SUPPORT_PRESETS && custom ? presets[custom] : {}; + if(DEBUG && !profile){ + + console.warn("Preset not found: " + custom); + } + // initialize worker if(SUPPORT_WORKER && (custom = options["worker"])){ @@ -296,11 +300,16 @@ const self = this; const threads = parseInt(custom, 10) || 4; + /** @private */ self._current_task = -1; + /** @private */ self._task_completed = 0; + /** @private */ self._task_result = []; + /** @private */ self._current_callback = null; //self._ids_count = new Array(threads); + /** @private */ self._worker = new Array(threads); for(let i = 0; i < threads; i++){ @@ -344,17 +353,14 @@ options["worker"] = false; - // if(SUPPORT_ASYNC){ - // - // options["async"] = true; - // } - + /** @private */ this._worker = null; } } // apply custom options + /** @private */ this.mode = ( options["mode"] || @@ -363,60 +369,77 @@ defaults.mode ); - if(SUPPORT_ASYNC) this.async = ( + if(SUPPORT_ASYNC) /** @private */ this.async = ( - options["async"] || - this.async || - defaults.async + is_undefined(custom = options["async"]) ? + + this.async || + defaults.async + : + custom ); - if(SUPPORT_WORKER) this.worker = ( + if(SUPPORT_WORKER) /** @private */ this.worker = ( - options["worker"] || - this.worker || - defaults.worker + is_undefined(custom = options["worker"]) ? + + this.worker || + defaults.worker + : + custom ); + /** @private */ this.threshold = ( - options["threshold"] || - profile.threshold || - this.threshold || - defaults.threshold + is_undefined(custom = options["threshold"]) ? + + profile.threshold || + this.threshold || + defaults.threshold + : + custom ); + /** @private */ this.depth = ( - options["depth"] || - profile.depth || - this.depth || - defaults.depth + is_undefined(custom = options["depth"]) ? + + profile.depth || + this.depth || + defaults.depth + : + custom ); - this.suggest = ( + if(SUPPORT_SUGGESTIONS){ - options["suggest"] || - this.suggest || - defaults.suggest - ); + /** @private */ + this.suggest = ( - custom = options["encode"] || profile.encode; + is_undefined(custom = options["suggest"]) ? + this.suggest || + defaults.suggest + : + custom + ); + } + + custom = is_undefined(custom = options["encode"]) ? + + profile.encode + : + custom; + + /** @private */ this.encoder = ( (custom && global_encoder[custom] && global_encoder[custom].bind(global_encoder)) || - (typeof custom === "function" ? custom : this.encoder || false) + (is_function(custom) ? custom : this.encoder || false) ); - if(DEBUG){ - - this.debug = ( - - options["debug"] || - this.debug - ); - } - if((custom = options["matcher"])) { this.addMatcher( @@ -428,42 +451,56 @@ if((custom = options["filter"])) { + /** @private */ this.filter = init_filter(filter[custom] || custom, this.encoder); } if((custom = options["stemmer"])) { + /** @private */ this.stemmer = init_stemmer(stemmer[custom] || custom, this.encoder); } // initialize primary index + /** @private */ this._map = create_object_array(10); + /** @private */ this._ctx = {}; + /** @private */ this._ids = {}; + /** @private */ this._stack = {}; + /** @private */ this._stack_keys = []; /** * @type {number|null} + * @private */ this._timer = 0; if(SUPPORT_CACHE) { + /** @private */ this._cache_status = true; + /** @private */ this.cache = custom = ( - options["cache"] || - this.cache || - defaults.cache + is_undefined(custom = options["cache"]) ? + + this.cache || + defaults.cache + : + custom ); + /** @private */ this._cache = custom ? - (new Cache(custom)) + new Cache(custom) : false; } @@ -563,7 +600,7 @@ /** * @param {number|string} id - * @param {?string} content + * @param {string} content * @param {boolean=} _skip_update * @this {FlexSearch} * @export @@ -571,7 +608,7 @@ FlexSearch.prototype.add = function(id, content, _skip_update){ - if(content && (typeof content === "string") && ((id /*&& !index_blacklist[id]*/) || (id === 0))){ + if(content && is_string(content) && ((id && !index_blacklist[id]) || (id === 0))){ // check if index ID already exist @@ -641,7 +678,7 @@ const words = ( - typeof tokenizer === "function" ? + is_function(tokenizer) ? tokenizer(content) :( @@ -796,7 +833,7 @@ // update status - this._ids[id] = "1"; + this._ids[id] = 1; if(SUPPORT_CACHE){ @@ -821,7 +858,7 @@ FlexSearch.prototype.update = function(id, content){ - if(this._ids[id] && content && (typeof content === "string")){ + if(this._ids[id] && is_string(content)){ if(PROFILER){ @@ -847,11 +884,11 @@ FlexSearch.prototype.remove = function(id){ - if(this._ids[id] /*&& !index_blacklist[id]*/){ + if(this._ids[id]){ if(SUPPORT_WORKER && this.worker){ - const current_task = parseInt(this._ids[id], 10); + const current_task = this._ids[id]; this._worker[current_task].postMessage(current_task, { @@ -919,27 +956,38 @@ * @param {!string} query * @param {number|Function=} limit * @param {Function=} callback - * @returns {Array|undefined} + * @param {boolean=} _recall + * @returns {Array|Promise|undefined} * @export */ - FlexSearch.prototype.search = function(query, limit, callback){ + FlexSearch.prototype.search = function(query, limit, callback, _recall){ + let _query = query; let threshold; let result = []; - if(typeof query === "object"){ + if(is_object(query)){ // re-assign properties - callback = query["callback"] || /** @type {?Function} */ (limit); + if(SUPPORT_ASYNC){ + + callback = query["callback"] || /** @type {?Function} */ (limit); + + if(callback) { + + _query["callback"] = null; + } + } + limit = query["limit"]; threshold = query["threshold"]; query = query["query"]; } /* - if(!index_blacklist[query]){ + if(index_blacklist[query]){ return result; } @@ -947,7 +995,7 @@ threshold || (threshold = this.threshold || 0); - if(typeof limit === "function"){ + if(is_function(limit)){ callback = limit; limit = 1000; @@ -986,31 +1034,42 @@ queue(function(){ - callback(self.search(query, limit)); + callback(self.search(_query, limit, null, true)); self = null; }, 1, "search-" + this.id); } else{ - callback(this.search(query, limit)); + callback(this.search(_query, limit, null, true)); } return; } + else if(SUPPORT_ASYNC && !_recall && this.async){ + + /** @type {FlexSearch} */ + let self = this; + + return new Promise(function(resolve){ + + resolve(self.search(_query, limit, null, true)); + self = null; + }); + } if(PROFILER){ profile_start("search"); } - if(!query || (typeof query !== "string")){ + if(!query || !is_string(query)){ return result; } /** @type {!string|Array} */ - let _query = query; + (_query = query); if(SUPPORT_CACHE && this.cache){ @@ -1050,7 +1109,7 @@ const words = ( - typeof tokenizer === "function" ? + is_function(tokenizer) ? tokenizer(_query) :( @@ -1077,8 +1136,9 @@ if(this.depth){ use_contextual = true; + // TODO: alternative roots ctx_root = words[0]; - check_words[ctx_root] = "1"; + check_words[ctx_root] = 1; } else{ @@ -1098,6 +1158,7 @@ if(value && !check_words[value]){ let map; + let map_value; let map_found = false; const map_check = []; let count = 0; @@ -1111,25 +1172,16 @@ ctx_map[ctx_root] : this._map - )[z]; - if(map[value]){ + if((map_value = map[value])){ - map_check[count++] = map[value]; + map_check[count++] = map_value; map_found = true; } } - if(!map_found){ - - if(!this.suggest){ - - found = false; - break; - } - } - else { + if(map_found){ // Not handled by intersection: @@ -1145,10 +1197,18 @@ // Handled by intersection: - // check[check.length] = map_check; + //check[check.length] = map_check; + } + else { + + if(!SUPPORT_SUGGESTIONS || !this.suggest){ + + found = false; + break; + } } - check_words[value] = "1"; + check_words[value] = 1; } ctx_root = value; @@ -1163,7 +1223,7 @@ // Not handled by intersection: - result = intersect(check, limit, this.suggest); + result = intersect(check, limit, SUPPORT_SUGGESTIONS && this.suggest); // Handled by intersection: @@ -1332,7 +1392,6 @@ * @dict {Function} * @private * @const - * @final */ const global_encoder = SUPPORT_ENCODER ? { @@ -1538,7 +1597,7 @@ //"balance": global_encoder_balance }; - // Xone Async Handler Fallback + // Async Handler const queue = SUPPORT_ASYNC ? (function(){ @@ -1569,14 +1628,19 @@ this.clear(); + /** @private */ this.limit = (limit !== true) && limit; } Cache.prototype.clear = function(){ + /** @private */ this.cache = {}; + /** @private */ this.count = {}; + /** @private */ this.index = {}; + /** @private */ this.ids = []; }; @@ -1727,13 +1791,12 @@ /** * @param {!string} str * @param {RegExp|Array} regex - * @param {string=} replacement * @returns {string} */ - function replace(str, regex, replacement){ + function replace(str, regex/*, replacement*/){ - if(typeof replacement === "undefined"){ + //if(is_undefined(replacement)){ for(let i = 0; i < /** @type {Array} */ (regex).length; i += 2){ @@ -1741,11 +1804,11 @@ } return str; - } - else{ - - return str.replace(/** @type {!RegExp} */ (regex), replacement); - } + // } + // else{ + // + // return str.replace(/** @type {!RegExp} */ (regex), replacement || ""); + // } } /** @@ -1829,7 +1892,7 @@ break; } - else if(typeof tmp[a] === "object"){ + else if(is_object(tmp[a])){ remove_index(tmp[a], id); } @@ -2142,9 +2205,9 @@ // loop through arrays let tmp, count = 0; - let z = 1; + let z = 0; // start from 1 - while(z < length_z){ + while(++z < length_z){ // get each array one by one @@ -2154,11 +2217,11 @@ suggestions = []; arr = arrays[z]; length = arr.length; - i = -1; + i = 0; while(i < length){ - tmp = arr[++i]; + tmp = arr[i++]; if(check[tmp]){ @@ -2190,11 +2253,10 @@ const current_suggestion = ( - suggestions[check_val] ? + suggestions[check_val] || ( - suggestions[check_val] - : suggestions[check_val] = [] + ) ); current_suggestion[current_suggestion.length] = tmp; @@ -2206,24 +2268,22 @@ break; } - - z++; } if(suggest){ count = result.length; - length = suggestions.length; + z = suggestions.length; - if(length && (!limit || (count < limit))){ + if(z && (!limit || (count < limit))){ - for(z = length - 1; z >= 0; z--){ + while(z--){ tmp = suggestions[z]; if(tmp){ - for(i = 0; i < tmp.length; i++){ + for(let i = 0, len = tmp.length; i < len; i++){ result[count++] = tmp[i]; @@ -2256,16 +2316,18 @@ } /** - * @param {!Array>} arrays + * @param {Array>|Array} arrays * @param {number=} limit + * @param {boolean=} suggest * @returns {Array} */ /* - function intersect_3d(arrays, limit) { + function intersect_3d(arrays, limit, suggest) { - const result = []; + let result = []; const length_z = arrays.length; + const check = {}; if(length_z > 1){ @@ -2275,43 +2337,38 @@ const arr_tmp = arrays[0]; - for(const a = 0; a < arr_tmp.length; a++){ + for(let a = 0, len = arr_tmp.length; a < len; a++){ // fill initial map - const check = {}; const arr = arr_tmp[a]; - const length = arr.length; - const i = 0; - while(i < length) { + for(let i = 0, length = arr.length; i < length; i++) { - check[arr[i++]] = 1; + check[arr[i]] = 1; } } // loop through arrays - const tmp, count = 0; - const z = 1; + let tmp, count = 0; + let z = 1; while(z < length_z){ // get each array one by one - const found = false; + let found = false; const arr_tmp = arrays[0]; - for(const a = 0; a < arr_tmp.length; a++){ + for(let a = 0, len = arr_tmp.length; a < len; a++){ - arr = arr_tmp[a]; - length = arr.length; - i = 0; + const arr = arr_tmp[a]; - while(i < length){ + for(let i = 0, length = arr.length; i < length; i++){ - if((check[tmp = arr[i++]]) === z){ + if((check[tmp = arr[i]]) === z){ // fill in during last round @@ -2436,6 +2493,16 @@ return val.constructor === Array; } + /** + * @param {*} val + * @returns {boolean} + */ + + function is_function(val){ + + return typeof val === "function"; + } + /** * @param {*} val * @returns {boolean} @@ -2443,7 +2510,7 @@ function is_object(val){ - return val.constructor === Object; + return typeof val === "object"; } /** @@ -2600,11 +2667,6 @@ if(data){ - // if(flexsearch.debug){ - // - // console.log("Worker Job Started: " + data["id"]); - // } - if(data["search"]){ const results = flexsearch["search"](data["content"], @@ -2650,10 +2712,7 @@ info["worker"] = id; - if(flexsearch.debug){ - - console.log(info); - } + console.log(info); /** @lends {Worker} */ //self.postMessage(info); @@ -2690,13 +2749,6 @@ callback(data["id"], data["content"], data["result"], data["limit"]); } - else{ - - if(DEBUG && options["debug"]){ - - console.log(data); - } - } }, // cores: @@ -2717,12 +2769,12 @@ return thread; } })( - // Xone Worker Handler Fallback + // Worker Handler SUPPORT_WORKER ? (function register_worker(){ const worker_stack = Object.create(null); - const inline_supported = !!((typeof Blob !== "undefined") && (typeof URL !== "undefined") && URL.createObjectURL); + const inline_supported = (typeof Blob !== "undefined") && (typeof URL !== "undefined") && URL.createObjectURL; return ( @@ -2766,7 +2818,7 @@ : // Load Extern Worker (but also requires CORS) - "../" + name + "." + RELEASE + ".js" + "../" + name + (RELEASE ? "." + RELEASE : "") + ".js" ); name += "-" + _id; diff --git a/flexsearch.light.js b/flexsearch.light.js index c36c2c6..57d5c6a 100644 --- a/flexsearch.light.js +++ b/flexsearch.light.js @@ -1,17 +1,17 @@ /* - FlexSearch v0.3.0 + FlexSearch v0.3.1 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(h,w,u){var r;(r=u.define)&&r.amd?r([],function(){return w}):(r=u.modules)?r[h.toLowerCase()]=w:"object"===typeof exports?module.exports=w:u[h]=w})("FlexSearch",function(){function h(a){a||(a=x);this.id=a.id||F++;this.init(a);w(this,"index",function(){return this.a});w(this,"length",function(){return Object.keys(this.a).length})}function w(a,b,c){Object.defineProperty(a,b,{get:c})}function u(a,b,c){if("undefined"===typeof c){for(c=0;c=d&&(a=a[f+.5>>0],a=a[c]||(a[c]=[]),a[a.length]=e);return f}function z(a,b){if(a)for(var c=Object.keys(a),e=0,f=c.length;ea?1:a?-1:0}function H(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function B(a){for(var b=Array(a), -c=0;cp;t--)g=m.substring(p,t),r(d,e,g,a,h,l,f);break;default:if(q=r(d,e,m,a,1,l,f),v&&1=f)for(q=e._ctx[m]||(e._ctx[m]={}),m=this.b[m]||(this.b[m]=B(10)),l=n-v,g=n+v+1,0>l&&(l=0),g>k&&(g=k);lb;b++)z(this.g[b],a);this.depth&&z(this.b,a); -delete this.a[a]}return this};h.prototype.search=function(a,b,c){var e=[];if("object"===typeof a){c=a.callback||b;b=a.limit;var f=a.threshold;a=a.query}f||(f=this.threshold||0);"function"===typeof b?(c=b,b=1E3):b||0===b||(b=1E3);if(c)c(this.search(a,b));else{if(!a||"string"!==typeof a)return e;a=this.encode(a);if(!a.length)return e;c=this.mode;c="function"===typeof c?c(a):a.split(C);var h=c.length,d=!0;a=[];var k={};if(1=f;u--)p=(n?q[m]:this.g)[u],p[g]&&(t[w++]=p[g],r=!0);if(r)a[a.length]=1b&&(e=e.slice(0,b)));return e}};h.prototype.clear=function(){this.destroy();return this.init()};h.prototype.destroy=function(){this.filter=this.stemmer=this.g=this.b=this.a=null;return this};var y={icase:function(a){return a.toLowerCase()}};return h}(!1),this); +'use strict';(function(d,t,q){var r;(r=q.define)&&r.amd?r([],function(){return t}):(r=q.modules)?r[d.toLowerCase()]=t:"object"===typeof exports?module.exports=t:q[d]=t})("FlexSearch",function(){function d(a){a||(a=v);this.id=a.id||G++;this.init(a);t(this,"index",function(){return this.a});t(this,"length",function(){return Object.keys(this.a).length})}function t(a,b,c){Object.defineProperty(a,b,{get:c})}function q(a,b){for(var c=0;c=g&&(a=a[f+.5>>0],a=a[c]||(a[c]=[]),a[a.length]=e);return f}function y(a,b){if(a)for(var c=Object.keys(a),e=0,f=c.length;ea?1:a?-1:0}function I(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function x(a){return"function"===typeof a}function z(a){return"undefined"=== +typeof a}function B(a){for(var b=Array(a),c=0;cp;q--)n=l.substring(p,q),r(g,e,n,a,t,m,f);break;default:if(d=r(g,e,l,a,1,m,f),u&&1=f)for(d=e._ctx[l]||(e._ctx[l]={}),l=this.b[l]||(this.b[l]=B(10)),m=k-u,n=k+u+1,0>m&&(m=0),n>h&&(n=h);mb;b++)y(this.f[b],a);this.depth&&y(this.b,a);delete this.a[a]}return this};d.prototype.search=function(a,b,c){var e=a,f=[];if("object"===typeof a){b=a.limit;var d=a.threshold;a=a.query}d||(d=this.threshold||0);x(b)?(c=b,b=1E3):b||0===b||(b=1E3);if(c)c(this.search(e,b,null,!0));else{if(!a||"string"!==typeof a)return f;e=this.encode(a);if(!e.length)return f;a=this.mode;a=x(a)?a(e):e.split(C);c=a.length;var g= +!0;e=[];var h={};if(1=d;v--)if(p=(k?q[l]:this.f)[v],p=p[n])t[w++]=p,r=!0;if(r)e[e.length]=1b&&(d=d.slice(0,b)));f=d}return f}};d.prototype.clear=function(){this.destroy();return this.init()};d.prototype.destroy=function(){this.filter=this.stemmer=this.f=this.b=this.a=null;return this};var w={icase:function(a){return a.toLowerCase()}};return d}(!1),this); diff --git a/flexsearch.min.js b/flexsearch.min.js index 3b44841..a318406 100644 --- a/flexsearch.min.js +++ b/flexsearch.min.js @@ -1,29 +1,36 @@ /* - FlexSearch v0.3.0 + FlexSearch v0.3.1 Copyright 2019 Nextapps GmbH Author: Thomas Wilkerling Released under the Apache 2.0 Licence https://github.com/nextapps-de/flexsearch */ -'use strict';(function(v,B,f){var w;(w=f.define)&&w.amd?w([],function(){return B}):(w=f.modules)?w[v.toLowerCase()]=B:"object"===typeof exports?module.exports=B:f[v]=B})("FlexSearch",function O(v){function f(a){"string"===typeof a&&(a=H[a]);a||(a=y);this.id=a.id||P++;this.init(a);w(this,"index",function(){return this.a});w(this,"length",function(){return Object.keys(this.a).length})}function w(a,b,e){Object.defineProperty(a,b,{get:e})}function d(a){return new RegExp(a,"g")}function x(a,b,e){if("undefined"=== -typeof e){for(e=0;e=g&&(a=a[k+.5>>0],a=a[e]||(a[e]=[]),a[a.length]=c);return k}function q(a,b){if(a)for(var e=Object.keys(a),c=0,k=e.length;c=(8=(8a?1:a?-1:0}function T(a,b){a=a.length-b.length;return 0>a?-1:a?1:0}function U(a,b,e){var c=[],k=[],d=a.length;if(1b&&(c=c.slice(0,b)));return c}function F(a){a.C||(a.C=J(function(){a.C=0;var b= -a.async;b&&(a.async=!1);if(a.c.length){for(var e=Date.now(),c;(c=a.c.shift())||0===c;){var d=a.f[c];switch(d[0]){case D.add:a.add(d[1],d[2]);break;case D.remove:a.remove(d[1])}delete a.f[c];if(100=d&&(c.m=c.b),c.A&&c.m===c.b&&(c.cache&&c.h.set(b,c.g),c.A(c.g),c.g=[]),c})}else a.worker=!1,this.i=null;this.mode=a.mode||e.mode||this.mode||y.mode;this.async=a.async||this.async||y.async;this.b=a.worker||this.b||y.b;this.threshold=a.threshold||e.threshold||this.threshold||y.threshold;this.depth=a.depth||e.depth||this.depth||y.depth;this.s=a.suggest||this.s||y.s;this.o=(b=a.encode||e.encode)&& -A[b]&&A[b].bind(A)||("function"===typeof b?b:this.o||!1);(b=a.matcher)&&this.addMatcher(b);if(b=a.filter)this.filter=Q(M[b]||b,this.o);if(b=a.stemmer)this.stemmer=R(N[b]||b,this.o);this.v=K(10);this.j={};this.a={};this.f={};this.c=[];this.C=0;this.u=!0;this.h=(this.cache=b=a.cache||this.cache||y.cache)?new W(b):!1;return this};f.prototype.encode=function(a){a&&G.length&&(a=x(a,G));a&&this.B.length&&(a=x(a,this.B));a&&this.o&&(a=this.o(a));a&&this.stemmer&&(a=x(a,this.stemmer));return a};f.prototype.addMatcher= -function(a){var b=this.B,e;for(e in a)a.hasOwnProperty(e)&&b.push(d(e),a[e]);return this};f.prototype.add=function(a,b,e){if(b&&"string"===typeof b&&(a||0===a))if(this.a[a]&&!e)this.update(a,b);else{if(this.b)return++this.l>=this.i.length&&(this.l=0),this.i[this.l].postMessage(this.l,{add:!0,id:a,content:b}),this.a[a]=""+this.l,this;if(this.async)return this.f[a]||(this.c[this.c.length]=a),this.f[a]=[D.add,a,b],F(this),this;b=this.encode(b);if(!b.length)return this;e=this.mode;b="function"===typeof e? -e(b):"ngram"===e?I(b):b.split(L);for(var c={_ctx:{}},d=this.threshold,u=this.depth,g=this.v,h=b.length,f=0;ft;r--)l=m.substring(t,r),z(g,c,l,a,q,p,d);break;default:if(n=z(g,c,m,a,1,p,d),u&&1=d)for(n=c._ctx[m]||(c._ctx[m]={}),m=this.j[m]|| -(this.j[m]=K(10)),p=f-u,l=f+u+1,0>p&&(p=0),l>h&&(l=h);pb;b++)q(this.v[b],a);this.depth&&q(this.j,a);delete this.a[a];this.u=!1}return this};f.prototype.search=function(a,b,e){var c=[];if("object"===typeof a){e=a.callback||b;b=a.limit;var d=a.threshold;a=a.query}d||(d=this.threshold||0);"function"===typeof b?(e=b,b=1E3):b||0===b||(b=1E3);if(this.b)for(this.A=e,this.m=0,this.g=[],c=0;c=d;A--)w=(p?t[l]:this.v)[A],w[r]&&(x[z++]=w[r],y=!0);if(y)m[m.length]= -1f;c--)h=g[c-1],g[c]=h,d[h]=c;g[f]=a;d[a]=f}}}return b};return a}();return f}(function(){var v=Object.create(null),B=!("undefined"===typeof Blob||"undefined"=== -typeof URL||!URL.createObjectURL);return function(f,w,d,x,z){var q=f;f=B?URL.createObjectURL(new Blob(["("+d.toString()+")()"],{type:"text/javascript"})):"../"+q+".min.js";q+="-"+w;v[q]||(v[q]=[]);v[q][z]=new Worker(f);v[q][z].onmessage=x;return{postMessage:function(d,f){v[q][d].postMessage(f)}}}}()),this); +'use strict';function J(g){var h=0;return function(){return h=e&&(b=b[A+.5>>0],b=b[a]||(b[a]=[]),b[b.length]=f);return A}function m(b,c){if(b)for(var a=Object.keys(b),f=0,A=a.length;f=(8=(8b?1:b?-1:0}function X(b,c){b=b.length-c.length;return 0>b?-1:b?1:0}function Y(b,c,a){var f=[],d=[],e=b.length;if(1c&&(f=f.slice(0,c)));return f}function E(b){return"string"===typeof b}function H(b){return"function"===typeof b}function x(b){return"undefined"===typeof b}function B(b){b.D||(b.D= +M(function(){b.D=0;var c=b.async;c&&(b.async=!1);if(b.b.length){for(var a=Date.now(),f;(f=b.b.shift())||0===f;){var d=b.c[f];switch(d[0]){case C.add:b.add(d[1],d[2]);break;case C.remove:b.remove(d[1])}delete b.c[f];if(100=d&&(f.m=f.h),f.B&&f.m===f.h&&(f.cache&&f.g.set(c,f.f),f.B(f.f),f.f=[]),f})}else b.worker=!1,this.i=null;this.mode=b.mode||a.mode||this.mode||w.mode;this.async=x(c=b.async)?this.async||w.async:c;this.h=x(c=b.worker)?this.h||w.h:c;this.threshold=x(c= +b.threshold)?a.threshold||this.threshold||w.threshold:c;this.depth=x(c=b.depth)?a.depth||this.depth||w.depth:c;this.v=x(c=b.suggest)?this.v||w.v:c;this.o=(c=x(c=b.encode)?a.encode:c)&&y[c]&&y[c].bind(y)||(H(c)?c:this.o||!1);(c=b.matcher)&&this.addMatcher(c);if(c=b.filter)this.filter=V(P[c]||c,this.o);if(c=b.stemmer)this.stemmer=Z(Q[c]||c,this.o);this.u=N(10);this.j={};this.a={};this.c={};this.b=[];this.D=0;this.s=!0;this.g=(this.cache=c=x(c=b.cache)?this.cache||w.cache:c)?new da(c):!1;return this}; +e.prototype.encode=function(b){b&&F.length&&(b=l(b,F));b&&this.C.length&&(b=l(b,this.C));b&&this.o&&(b=this.o(b));b&&this.stemmer&&(b=l(b,this.stemmer));return b};e.prototype.addMatcher=function(b){var c=this.C,d;for(d in b)b.hasOwnProperty(d)&&c.push(a(d),b[d]);return this};e.prototype.add=function(b,c,a){if(c&&E(c)&&(b&&!R[b]||0===b))if(this.a[b]&&!a)this.update(b,c);else{if(this.h)return++this.l>=this.i.length&&(this.l=0),this.i[this.l].postMessage(this.l,{add:!0,id:b,content:c}),this.a[b]=""+ +this.l,this;if(this.async)return this.c[b]||(this.b[this.b.length]=b),this.c[b]=[C.add,b,c],B(this),this;c=this.encode(c);if(!c.length)return this;a=this.mode;c=H(a)?a(c):"ngram"===a?D(c):c.split(O);for(var f={_ctx:{}},e=this.threshold,g=this.depth,k=this.u,r=c.length,t=0;tu;v--)q=l.substring(u,v),d(k,f,q,b,m,p,e);break;default:if(n=d(k,f,l,b,1,p,e),g&&1=e)for(n=f._ctx[l]||(f._ctx[l]={}),l=this.j[l]||(this.j[l]=N(10)),p=t-g,q=t+g+1,0>p&&(p=0),q>r&&(q=r);pc;c++)m(this.u[c],b);this.depth&&m(this.j,b);delete this.a[b];this.s=!1}return this};e.prototype.search=function(b,c,a,f){var d=b,e=[];if("object"===typeof b){(a=b.callback||c)&&(d.callback=null);c=b.limit;var g=b.threshold;b=b.query}g||(g=this.threshold||0);H(c)?(a=c,c=1E3):c||0===c||(c=1E3);if(this.h)for(this.B=a,this.m=0,this.f=[],e=0;e=g;I--)if(G=(m?w[v]:this.u)[I],G=G[y])B[F++]=G,C=!0;if(C)p[p.length]=1e;c--)k=g[c-1],g[c]=k,d[k]=c;g[e]=a;d[a]=e}}}return b};return a}();return e}(function(){var g=Object.create(null),h="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;return function(e,k,a,l,d){var m=e;e=h?URL.createObjectURL(new Blob(["("+a.toString()+")()"],{type:"text/javascript"})):"../"+m+".min.js";m+="-"+k;g[m]||(g[m]=[]);g[m][d]=new Worker(e);g[m][d].onmessage=l;return{postMessage:function(a,d){g[m][a].postMessage(d)}}}}()),this); diff --git a/package.json b/package.json index 867ac8c..694586e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flexsearch", - "version": "0.3.0", + "version": "0.3.1", "description": "Next-Generation full text search library with zero dependencies.", "homepage": "https://github.com/nextapps-de/flexsearch/", "author": "Thomas Wilkerling", @@ -24,10 +24,10 @@ "url": "https://github.com/nextapps-de/flexsearch.git" }, "scripts": { - "build": "node compile RELEASE=min DEBUG=false PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-light": "node compile RELEASE=light DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-compact": "node compile RELEASE=compact DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=false SUPPORT_PRESETS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", - "build-custom": "node compile RELEASE=custom DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build": "node compile RELEASE=min DEBUG=false PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-light": "node compile RELEASE=light DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_SUGGESTIONS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-compact": "node compile RELEASE=compact DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_PRESETS=true SUPPORT_SUGGESTIONS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", + "build-custom": "node compile RELEASE=custom DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESETS=false SUPPORT_SUGGESTIONS=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false", "build-lang": "node compile RELEASE=lang", "build-all": "npm run build && npm run build-light && npm run build-compact && npm run build-lang", "test-production": "nyc --reporter=html --reporter=text mocha --timeout=3000 test --exit", diff --git a/test/benchmark.html b/test/benchmark.html index 7165d9a..2fe8b50 100644 --- a/test/benchmark.html +++ b/test/benchmark.html @@ -17,7 +17,7 @@

Benchmark Comparison

- +

Indexed Text: "Gulliver's Travels" (Swift Jonathan 1726)


@@ -370,15 +370,23 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least target.innerHTML = html; } + var is_mobile = navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/); + function init_tests(index, keys){ var key = keys[index]; + var test = tests[key]; - tests[key].init(); + test.init(); + + if(is_mobile && (test.loops > 1)){ + + test.loops = (test.loops / 5) >> 0; + } for(var i = 0; i < text_data.length; i++){ - tests[key].add(i, text_data[i]); + test.add(i, text_data[i]); } document.getElementById("test-" + key).textContent = "ready ..."; @@ -389,24 +397,24 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least init_tests(index, keys); - }, 50); + }, 100); } else{ + /* window.start = function(){ start_tests(0, Object.keys(tests)); }; document.getElementById("btn_start").disabled = false; + */ - /* setTimeout(function(){ start_tests(0, keys); - }, 50); - */ + }, 1000); } } @@ -415,9 +423,9 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least var queries = text_queries; var len = queries.length; var key = keys[index]; - var current = tests[key]; - var loops = current.loops; - var query = current.query; + var test = tests[key]; + var loops = test.loops; + var query = test.query; var start = Date.now(); @@ -435,7 +443,7 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least console.log(key + ":", duration); - document.getElementById("test-" + key).textContent = format_number((1000 / duration * loops + 0.5) >> 0) + " op/s"; + document.getElementById("test-" + key).textContent = /*format_number*/((1000 / duration * loops + 0.5) >> 0) + " op/s"; if(++index < keys.length){ @@ -443,7 +451,7 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least start_tests(index, keys); - }, 50); + }, 1000); } } @@ -453,7 +461,7 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least init_tests(0, Object.keys(tests)); - }, 50); + }, 100); function format_number(num){ @@ -462,7 +470,7 @@ Test rules: 1. no cache allowed, 2. no async allowed, 3. should return at least // --------------------------------------- - window.tests = tests; + //window.tests = tests; })(); diff --git a/test/test.js b/test/test.js index c370734..2bad08b 100644 --- a/test/test.js +++ b/test/test.js @@ -513,18 +513,42 @@ if(env !== "light"){ flexsearch_async.update(1, "foo"); expect(flexsearch_async.length).to.equal(3); - expect(flexsearch_async.search("foo")).to.not.have.members([2, 1]); - expect(flexsearch_async.search("bar")).to.not.include(0); - expect(flexsearch_async.search("bar")).to.include(2); - expect(flexsearch_async.search("foobar")).to.not.include(2); + + flexsearch_async.search("foo").then(function(result){ + expect(result).to.not.have.members([2, 1]); + }); + + flexsearch_async.search("bar").then(function(result){ + expect(result).to.not.include(0); + }); + + flexsearch_async.search("bar").then(function(result){ + expect(result).to.include(2); + }); + + flexsearch_async.search("foobar").then(function(result){ + expect(result).to.not.include(2); + }); setTimeout(function(){ expect(flexsearch_async.length).to.equal(3); - expect(flexsearch_async.search("foo")).to.have.members([2, 1]); - expect(flexsearch_async.search("bar")).to.include(0); - expect(flexsearch_async.search("bar")).to.not.include(2); - expect(flexsearch_async.search("foobar")).to.include(2); + + flexsearch_async.search("foo", function(result){ + expect(result).to.have.members([2, 1]); + }); + + flexsearch_async.search("bar", function(result){ + expect(result).to.include(0); + }); + + flexsearch_async.search("bar", function(result){ + expect(result).to.not.include(2); + }); + + flexsearch_async.search("foobar", function(result){ + expect(result).to.include(2); + }); done(); @@ -546,10 +570,22 @@ if(env !== "light"){ setTimeout(function(){ expect(flexsearch_async.length).to.equal(3); - expect(flexsearch_async.search("foo")).to.have.members([2, 1]); - expect(flexsearch_async.search("bar")).to.include(0); - expect(flexsearch_async.search("bar")).to.not.include(2); - expect(flexsearch_async.search("foobar")).to.include(2); + + flexsearch_async.search("foo").then(function(result){ + expect(result).to.have.members([2, 1]); + }); + + flexsearch_async.search("bar").then(function(result){ + expect(result).to.include(0); + }); + + flexsearch_async.search("bar").then(function(result){ + expect(result).to.not.include(2); + }); + + flexsearch_async.search("foobar").then(function(result){ + expect(result).to.include(2); + }); done(); @@ -570,9 +606,18 @@ if(env !== "light"){ setTimeout(function(){ expect(flexsearch_async.length).to.equal(0); - expect(flexsearch_async.search("foo")).to.have.lengthOf(0); - expect(flexsearch_async.search("bar")).to.have.lengthOf(0); - expect(flexsearch_async.search("foobar")).to.have.lengthOf(0); + + flexsearch_async.search("foo", function(result){ + expect(result).to.have.lengthOf(0); + }); + + flexsearch_async.search("bar", function(result){ + expect(result).to.have.lengthOf(0); + }); + + flexsearch_async.search("foobar", function(result){ + expect(result).to.have.lengthOf(0); + }); done(); @@ -767,6 +812,8 @@ if(env !== "light"){ it("Should have been removed from the index", function(done){ + expect(flexsearch_worker.length).to.equal(3); + flexsearch_worker.remove(0); flexsearch_worker.remove(2); flexsearch_worker.remove(1); @@ -1039,28 +1086,31 @@ describe("Relevance", function(){ // Suggestion Tests // ------------------------------------------------------------------------ -describe("Suggestion", function(){ +if(env !== "light"){ - it("Should have been suggested properly by relevance", function(){ + describe("Suggestion", function(){ - var index = new FlexSearch({ - encode: "advanced", - mode: "strict", - suggest: true + it("Should have been suggested properly by relevance", function(){ + + var index = new FlexSearch({ + encode: "advanced", + mode: "strict", + suggest: true + }); + + index.add(0, "1 2 3 2 4 1 5 3"); + index.add(1, "zero one two three four five six seven eight nine ten"); + index.add(2, "four two zero one three ten five seven eight six nine"); + + expect(index.search("1 3 4 7")).to.have.members([0]); + expect(index.search("1 3 9 7")).to.have.members([0]); + expect(index.search("one foobar two")).to.have.members([1, 2]); + expect(index.search("zero one foobar two foobar")).to.have.members([1, 2]); + //TODO + //expect(index.search("zero one foobar two foobar")[0]).to.equal(1); }); - - index.add(0, "1 2 3 2 4 1 5 3"); - index.add(1, "zero one two three four five six seven eight nine ten"); - index.add(2, "four two zero one three ten five seven eight six nine"); - - expect(index.search("1 3 4 7")).to.have.members([0]); - expect(index.search("1 3 9 7")).to.have.members([0]); - expect(index.search("one foobar two")).to.have.members([1, 2]); - expect(index.search("zero one foobar two foobar")).to.have.members([1, 2]); - //TODO - //expect(index.search("zero one foobar two foobar")[0]).to.equal(1); }); -}); +} // ------------------------------------------------------------------------ // Feature Tests