From 41398573ca005d9a16223ba15fd65c948b8dbe96 Mon Sep 17 00:00:00 2001 From: Thomas Wilkerling Date: Tue, 18 May 2021 13:26:59 +0200 Subject: [PATCH] added support for export and import indexes --- dist/flexsearch.min.js | 43 +++---- doc/0.7.0.md | 73 +++++++++++- src/document.js | 97 ++++++---------- src/index.js | 27 ++++- src/intersect.js | 37 +++--- src/serialize.js | 249 +++++++++++++++++++++++++++++++++++++++++ src/webpack.js | 11 +- 7 files changed, 427 insertions(+), 110 deletions(-) create mode 100644 src/serialize.js diff --git a/dist/flexsearch.min.js b/dist/flexsearch.min.js index a343dc3..6911ef1 100644 --- a/dist/flexsearch.min.js +++ b/dist/flexsearch.min.js @@ -5,24 +5,27 @@ * Licence: Apache-2.0 * https://github.com/nextapps-de/flexsearch */ -(function(){var q;function u(a){for(var b=Array(a),c=0;c=b)return f.concat(d.slice(0,b-e));f=f.concat(d);e+=h}return f};function Q(a){this.h=!0!==a&&a;this.cache=B();this.g=[]}function R(a,b,c){"object"===typeof a&&(a=a.query);var d=this.cache.get(a);d||(d=this.search(a,b,c),this.cache.set(a,d));return d}Q.prototype.set=function(a,b){if(!this.cache[a]){var c=this.g.length;c===this.h?delete this.cache[this.g[c-1]]:c++;for(--c;0=e&&(g=e-1);this.o=e;this.threshold=g;this.A=b=c&&c.G||a.tokenize||"strict";this.depth="strict"===b&&h.depth;this.v=T(h.bidirectional,!0);this.m=f="memory"===a.optimize; -this.s=T(a.fastupdate,!0);this.l=a.minlength||1;this.g=f?u(e-g):B();e=h.resolution||e;g=h.threshold||g;g>=e&&(g=e-1);this.h=e;this.j=g;this.i=f?u(e-g):B();this.C=c&&c.C||a.rtl;this.B=(b=a.matcher||d&&d.B)&&E(b,!1);this.D=(b=a.stemmer||d&&d.D)&&E(b,!0);this.filter=(b=a.filter||d&&d.filter)&&ca(b);this.cache=(b=a.cache)&&new Q(b);this.u=(b=a.worker)&&new Worker("worker.js",{type:"module"});b&&(this.u.onmessage=function(k){console.log(k.data)},this.u.postMessage({H:"register",options:a}))} +(function(){'use strict';var q;var t=/[\W_]+/;function aa(a){if(a=a.toLowerCase())if(a&&this.B&&(a=B(a,this.B)),this.D&&1=b)return h.concat(c.slice(0,b-g));h=h.concat(c);g+=e}return h};function R(a){this.h=!0!==a&&a;this.cache=D();this.g=[]}function ea(a,b,c){"object"===typeof a&&(a=a.query);var d=this.cache.get(a);d||(d=this.search(a,b,c),this.cache.set(a,d));return d}R.prototype.set=function(a,b){if(!this.cache[a]){var c=this.g.length;c===this.h?delete this.cache[this.g[c-1]]:c++;for(--c;0=f&&(g=f-1);this.u=f;this.threshold=g;this.A=b=c&&c.G||a.tokenize||"strict";this.depth="strict"===b&&h.depth;this.v=T(h.bidirectional,!0);this.l=e="memory"===a.optimize; +this.i=T(a.fastupdate,!0);this.s=a.minlength||1;this.g=e?C(f-g):D();f=h.resolution||f;g=h.threshold||g;g>=f&&(g=f-1);this.j=f;this.m=g;this.h=e?C(f-g):D();this.C=c&&c.C||a.rtl;this.B=(b=a.matcher||d&&d.B)&&F(b,!1);this.D=(b=a.stemmer||d&&d.D)&&F(b,!0);this.filter=(b=a.filter||d&&d.filter)&&ca(b);this.cache=(b=a.cache)&&new R(b);this.o=(b=a.worker)&&new Worker("worker.js",{type:"module"});b&&(this.o.onmessage=function(k){console.log(k.data)},this.o.postMessage({H:"register",options:a}))} function T(a,b){return"undefined"!==typeof a?a:b}q=S.prototype;q.append=function(a,b){return this.add(a,b,!0)}; -q.add=function(a,b,c){if(this.register[a]&&!c)return this.update(a,b);if(b&&(a||0===a)){b=this.encode(b);var d=b.length;if(d){for(var f=this.depth,h=this.o-this.threshold,e=B(),g=B(),k=0;k=this.l&&(f||!e[l])){var p=Math.min(this.o/d*k|0,k);if(pm;v--)n=l.substring(m,v),n.length>=this.l&&U(this,e,n,t,a,c)}break}case "reverse":if(2< -r){for(m=r-1;0=this.l&&U(this,e,n,p,a,c);n=""}case "forward":if(1=this.l&&U(this,e,n,p,a,c);break;default:if(U(this,e,l,p,a,c),f&&1=this.l&&!p[l]){if(p[l]=1,v=Math.min((this.h-m)/d*k+t|0,k+(t-1)),vn;U(this,g,x?n:l,v,a,c,x?l:n)}}else m=Math.min(m+1,d-k)}}}}this.s||(this.register[a]=1)}}return this}; -function U(a,b,c,d,f,h,e){var g=e?a.i:a.g;if(!b[c]||e&&!b[c][e])a.m&&(g=g[d]),e?(b[c]||(b[c]=B()),b[c][e]=1,g=g[e]||(g[e]=B())):b[c]=1,g=g[c]||(g[c]=[]),a.m||(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))} -q.search=function(a,b,c){"object"===typeof a?(c=a,a=c.query):"object"===typeof b&&(c=b);var d=[],f=this.threshold;if(c){b=c.limit;f=T(c.threshold,f);var h=c.context;var e=c.suggest}if(a){a=this.encode(a);var g=a.length;if(1=this.l&&!c[p])if(this.m||e||this.g[p])k[r++]=p,c[p]=1;else return d;a=k;g=a.length}}if(!g)return d;b||(b=100);c=this.o-f;f=this.h-f;h=this.depth&&1b?d.slice(0,b):d}}return P(d,b,e)};function ha(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a} -function fa(a,b,c,d,f,h,e,g){var k=[],l=g?a.i:a.g;a.m||(l=ha(l,e,g,a.v));if(l){var r=0;d=Math.min(l.length,d);for(var p=0,n=0,m;p=f)));p++);if(r){if(h)return k=1===r?k[0]:[].concat.apply([],k),k.length>f?k.slice(0,f):k;b[b.length]=k;return}}return!c&&k}q.contain=function(a){return!!this.register[a]};q.update=function(a,b){return this.remove(a).add(a,b)}; -q.remove=function(a,b){var c=this.register[a];if(c){if(this.s)for(var d=0,f;dp&&(a=a.slice(0,p)),k&&this.store&&(a=ja.call(this,a)),e={tag:e,result:a}):e=void 0;e&&(d[d.length]=e, -h++)}return h?d:[]}}e||(e=this.h);l=l&&(1=this.s&&(e||!f[l])){var r=Math.min(this.u/d*k|0,k);if(rm;w--)p=l.substring(m,w),p.length>=this.s&&U(this,f,p,u,a,c)}break}case "reverse":if(2< +n){for(m=n-1;0=this.s&&U(this,f,p,r,a,c);p=""}case "forward":if(1=this.s&&U(this,f,p,r,a,c);break;default:if(U(this,f,l,r,a,c),e&&1=this.s&&!r[l]){if(r[l]=1,w=Math.min((this.j-m)/d*k+u|0,k+(u-1)),wp;U(this,g,v?p:l,w,a,c,v?l:p)}}else m=Math.min(m+1,d-k)}}}}this.i||(this.register[a]=1)}}return this}; +function U(a,b,c,d,e,h,f){var g=f?a.h:a.g;if(!b[c]||f&&!b[c][f])a.l&&(g=g[d]),f?(b[c]||(b[c]=D()),b[c][f]=1,g=g[f]||(g[f]=D())):b[c]=1,g=g[c]||(g[c]=[]),a.l||(g=g[d]||(g[d]=[])),h&&-1!==g.indexOf(e)||(g[g.length]=e,a.i&&(a=a.register[e]||(a.register[e]=[]),a[a.length]=g))} +q.search=function(a,b,c){"object"===typeof a?(c=a,a=c.query):"object"===typeof b&&(c=b);var d=[],e=this.threshold,h=0;if(c){b=c.limit;h=c.offset||0;e=T(c.threshold,e);var f=c.context;var g=c.suggest}if(a){a=this.encode(a);var k=a.length;if(1=this.s&&!c[p])if(this.l||g||this.g[p])l[r++]=p,c[p]=1;else return d;a=l;k=a.length}}if(!k)return d;b||(b=100);c=this.u-e;e=this.j-e;f=this.depth&&1b?d.slice(0,b):d}}return da(d,b,h,g)};function ka(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a} +function ja(a,b,c,d,e,h,f,g){var k=[],l=g?a.h:a.g;a.l||(l=ka(l,f,g,a.v));if(l){var n=0;d=Math.min(l.length,d);for(var r=0,p=0,m;r=e)));r++);if(n){if(h)return k=1===n?k[0]:[].concat.apply([],k),k.length>e?k.slice(0,e):k;b[b.length]=k;return}}return!c&&k}q.contain=function(a){return!!this.register[a]};q.update=function(a,b){return this.remove(a).add(a,b)}; +q.remove=function(a,b){var c=this.register[a];if(c){if(this.i)for(var d=0,e;da||c)g=g.slice(c,c+a);l&&(g=ma.call(this,g));h={tag:h, +result:g}}else h=void 0;h&&(d[d.length]=h,f++)}return f?d:[]}}g||(g=this.g);n=n&&(1 What is not included yet but comes soon? - Worker (almost done) -- Pagination (not implemented yet) -- Export/Import (not implemented yet) +- Offset-Pagination (not implemented yet) +- ~~Export/Import (not implemented yet)~~ - Engines (almost done) -- Tags (almost done) -- Bundles: Light, Compact, Full (almost done) +- ~~Tags (almost done)~~ +- ~~Bundles: Light, Compact, Full (almost done)~~ - Test Automation (needs to be migrated) - Benchmark Suite (almost done) @@ -79,6 +79,7 @@ What will be dropped? - Where-Clause - Index Information `index.info()` +- Paging Cursor (gets replaced by offset) ## Builtin Profiles @@ -1029,6 +1030,70 @@ When you perform a field search through all fields then this task is perfectly b The main thread has to solve a last intersection calculation as before. On this step it needs to apply "bool" and "paging" logic, also "suggestions". I'm thinking about to move the workload from the main tread to another worker, so all computations will perform in background completely, the index from the main thread just holds the configuration and its document store (when using store). +## Export / Import + +### Export + +The export has slightly changed. The export now consist of several smaller parts, instead of just one large bulk. You need to pass a callback function which has 2 arguments "key" and "data". This callback function is called by each part, e.g.: + +```js +index.export(function(key, data){ + + // you need to store both the key and the data! + // e.g. use the key for the filename and save your data + + localStorage.setItem(key, data); +}); +``` + +Exporting data to the localStorage isn't really a good practice, but if size is not a concern than use it if you like. The export primarily exists for the usage in Node.js or to store indexes you want to delegate from a server to the client. + +> The size of the export corresponds to the memory consumption of the library. To reduce export size you have to use a configuration which has less memory footprint (use the table at the bottom to get information about configs and its memory allocation). + +When your save routine runs asynchronously you have to return a promise: + +```js +index.export(function(key, data){ + + return new Promise(function(resolve){ + + // do the saving as async + + resolve(); + }); +}); +``` + +> You cannot export the additional table for the "fastupdate" feature. These table exists of references and when stored they fully get serialized and becomes too large. The lib will handle these automatically for you. When importing data, the index automatically disables "fastupdate". + +### Import + +Before you can import data, you need to create your index first. For document indexes provide the same document descriptor you used when export the data. This configuration isn't stored in the export. + +```js +var index = new Index({ ... }); +``` + +To import the data just pass a key and data: + +```js +index.import(key, localStorage.getItem(key)); +``` + +You need to import every key! Otherwise, your index does not work. You need to store the keys from the export and use this keys for the import (the order of the keys can differ). + +This is just for demonstration and is not recommended, because you might have other keys in your localStorage which aren't supported as an import: + +```js +var keys = Object.keys(localStorage); + +for(let i = 0, key; i < keys.length; i++){ + + key = keys[i]; + index.import(key, localStorage.getItem(key)); +} +``` + ## Engines (Custom Indexes) FlexSearch supports custom engines for the index. The default engine is `Index` which extends the abstract class `Engine` under the hood. These abstract class provides some basic methods like cache and async handler. It needs to just implement the 5 standard functions `add`, `append`, `update`, `remove` and `search`. Then you can use this new engine fully integrated into FlexSearch workflow (Document Handler, Worker, Async Handler, Cache, Document Storage, Paging). That it also some demonstration of the powerful flexibility of extending FlexSearch. diff --git a/src/document.js b/src/document.js index 839472b..5cfc0e9 100644 --- a/src/document.js +++ b/src/document.js @@ -6,12 +6,13 @@ * https://github.com/nextapps-de/flexsearch */ -import { SUPPORT_ASYNC, SUPPORT_CACHE, SUPPORT_STORE, SUPPORT_TAGS } from "./config.js"; +import { SUPPORT_ASYNC, SUPPORT_CACHE, SUPPORT_SERIALIZE, SUPPORT_STORE, SUPPORT_TAGS } from "./config.js"; import Index from "./index.js"; import Cache, { searchCache } from "./cache.js"; import { create_object } from "./common.js"; import { addAsync, appendAsync, removeAsync, searchAsync, updateAsync } from "./async.js"; import { intersect, intersect_union } from "./intersect.js"; +import { exportDocument, importDocument } from "./serialize.js"; /** * @param {Object=} options @@ -55,7 +56,6 @@ function Document(options){ options["cache"] = false; } - /** @private */ this.index = parse_descriptor.call(this, options); } @@ -73,7 +73,7 @@ function parse_option(value, default_value){ function parse_descriptor(options){ const index = create_object(); - let field = options["doc"]; // options["document"] + let field = options["doc"]; let field_options; if(typeof field === "string"){ @@ -377,11 +377,20 @@ Document.prototype.remove = function(id){ for(let i = 0; i < this.field.length; i++){ this.index[this.field[i]].remove(id, true); + + if(this.fastupdate){ + + // when fastupdate was enabled all ids will + // be already cleanup after the first loop + + break; + } } if(SUPPORT_TAGS && this.tag){ - // when fastupdate was enabled the id will be already cleanup by the index + // when fastupdate was enabled the id will + // be already cleanup by the index if(!this.fastupdate){ @@ -428,9 +437,9 @@ Document.prototype.search = function(query, limit, options){ options = limit; } - let result = []; + let result = [], result_field = []; let pluck, enrich; - let field, field_options, tag, bool, count = 0; + let field, field_options, tag, bool, offset, count = 0; if(options){ @@ -440,6 +449,7 @@ Document.prototype.search = function(query, limit, options){ enrich = SUPPORT_STORE && this.store && options["enrich"]; bool = options["bool"] === "and"; limit = options["limit"]; + offset = options["offset"]; if(field){ @@ -468,7 +478,7 @@ Document.prototype.search = function(query, limit, options){ for(let i = 0, res; i < tag.length; i++){ - res = get_tag.call(this, tag[i], limit || 100, enrich); + res = get_tag.call(this, tag[i], limit || 100, offset || 0, enrich); if(res){ @@ -485,32 +495,19 @@ Document.prototype.search = function(query, limit, options){ field || (field = this.field); bool = bool && ((field.length > 1) || (tag && (tag.length > 1))); - let found_tag = []; - // TODO solve this in one loop below - for(let i = 0, res, key, item, len; i < field.length; i++){ + for(let i = 0, res, key, len; i < field.length; i++){ key = field[i]; - // if(field_options){ - // - // item = field_options[key]; - // - // // inherit options also when search? it is just for laziness, Object.assign() has a cost - // //item = typeof item === "object" ? Object.assign({}, options, item) : options; - // } - // else{ - // - // item = options; - // } + // inherit options also when search? it is just for laziness, Object.assign() has a cost res = this.index[key].search(query, limit, field_options ? field_options[key] : options); len = res.length; if(tag && len){ - const field_tag = found_tag[i] = []; const arr = []; let count = 0; @@ -529,8 +526,8 @@ Document.prototype.search = function(query, limit, options){ if(len){ + count++; arr[arr.length] = bool ? [res] : res; - field_tag[count++] = key; } } @@ -538,7 +535,7 @@ Document.prototype.search = function(query, limit, options){ if(bool){ - res = intersect(arr, limit || 100); + res = intersect(arr, limit || 100, offset || 0); } else{ @@ -551,18 +548,12 @@ Document.prototype.search = function(query, limit, options){ if(len){ + result_field[count] = key; result[count++] = res; } else if(bool){ - //if(!len){ - - return []; - //} - - // add a pseudo relevance index for the intersection - // used when squash the results on boolean "and" - //res = [res]; + return []; } } @@ -573,20 +564,6 @@ Document.prototype.search = function(query, limit, options){ return []; } - // squash the results on boolean "and"? - - // if(bool){ - // - // limit || (limit = 100); - // - // if(enrich && this.store){ - // - // return apply_enrich.call(this, intersect(result, limit)); - // } - // - // return intersect(result, limit); - // } - if(pluck && (!enrich || !this.store)){ // fast path optimization @@ -594,9 +571,8 @@ Document.prototype.search = function(query, limit, options){ return result[0]; } - for(let i = 0, res, key; i < field.length; i++){ + for(let i = 0, res; i < result_field.length; i++){ - key = field[i]; res = result[i]; if(res.length){ @@ -612,16 +588,11 @@ Document.prototype.search = function(query, limit, options){ return res; } - result[i] = res = { + result[i] = { - "field": key, + "field": result_field[i], "result": res }; - - if(tag){ - - res["tag"] = found_tag[i]; - } } return result; @@ -631,16 +602,16 @@ Document.prototype.search = function(query, limit, options){ * @this Document */ -function get_tag(key, limit, enrich){ +function get_tag(key, limit, offset, enrich){ let res = this.tagindex[key]; - let len = res && res.length; + let len = res && (res.length - offset); - if(len){ + if(len && (len > 0)){ - if(len > limit){ + if((len > limit) || offset){ - res = res.slice(0, limit); + res = res.slice(offset, offset + limit); } if(enrich){ @@ -709,4 +680,10 @@ if(SUPPORT_ASYNC){ Document.prototype.searchAsync = searchAsync; Document.prototype.updateAsync = updateAsync; Document.prototype.removeAsync = removeAsync; +} + +if(SUPPORT_SERIALIZE){ + + Document.prototype.export = exportDocument; + Document.prototype.import = importDocument; } \ No newline at end of file diff --git a/src/index.js b/src/index.js index fd2bbe0..d7c2bb4 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,14 @@ * https://github.com/nextapps-de/flexsearch */ -import { SUPPORT_PRESET, SUPPORT_CACHE, SUPPORT_ASYNC, SUPPORT_WORKER, SUPPORT_SUGGESTION } from "./config.js"; +import { + SUPPORT_PRESET, + SUPPORT_CACHE, + SUPPORT_ASYNC, + SUPPORT_WORKER, + SUPPORT_SUGGESTION, + SUPPORT_SERIALIZE +} from "./config.js"; import { encode as default_encoder } from "./lang/latin/default.js"; import { create_object, create_object_array, concat, sort_by_length_down } from "./common.js"; import { pipeline, init_stemmer_or_matcher, init_filter } from "./lang.js"; @@ -15,6 +22,7 @@ import { addAsync, appendAsync, removeAsync, searchAsync, updateAsync } from "./ import { intersect } from "./intersect.js"; import Cache, { searchCache } from "./cache.js"; import apply_preset from "./presets.js"; +import { exportIndex, importIndex } from "./serialize.js"; /** * @param {Object=} options @@ -377,11 +385,12 @@ Index.prototype.search = function(query, limit, options){ let result = []; let length; - let threshold = this.threshold, context, suggest; + let threshold = this.threshold, 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"]; @@ -512,12 +521,14 @@ Index.prototype.search = function(query, limit, options){ result = concat(result); } + // TODO apply offset + return result.length > limit ? result.slice(0, limit) : result; } } } - return intersect(result, limit, suggest); + return intersect(result, limit, offset, suggest); }; function get_array(arr, term, keyword, bidirectional){ @@ -579,6 +590,8 @@ Index.prototype.add_result = function(result, suggest, resolution, limit, just_o if(tmp){ + // TODO apply offset + // keep score (sparse array): //word_arr[x] = arr; @@ -603,6 +616,8 @@ Index.prototype.add_result = function(result, suggest, resolution, limit, just_o if(just_one_loop){ + // TODO apply offset + // fast path optimization if(count === 1){ @@ -765,4 +780,10 @@ if(SUPPORT_ASYNC){ Index.prototype.searchAsync = searchAsync; Index.prototype.updateAsync = updateAsync; Index.prototype.removeAsync = removeAsync; +} + +if(SUPPORT_SERIALIZE){ + + Index.prototype.export = exportIndex; + Index.prototype.import = importIndex; } \ No newline at end of file diff --git a/src/intersect.js b/src/intersect.js index 0dab346..52202c7 100644 --- a/src/intersect.js +++ b/src/intersect.js @@ -3,32 +3,16 @@ import { create_object, concat } from "./common.js"; /** * @param arrays * @param limit + * @param offset * @param {boolean|Array=} suggest * @returns {Array} */ -export function intersect(arrays, limit, suggest) { +export function intersect(arrays, limit, offset, suggest) { const length = arrays.length; let result = []; - // if(!length){ - // - // return result; - // } - // - // if(length === 1){ - // - // const tmp = arrays[0]; - // - // if(tmp.length === 1){ - // - // return tmp[0]; - // } - // - // return concat(tmp); - // } - // arrays.sort(function(a, b){ // // return a.length - b.length; @@ -78,13 +62,20 @@ export function intersect(arrays, limit, suggest) { if(x === (length - 1)){ - result[count++] = id; + if(offset){ - if(count === limit){ + offset--; + } + else{ - // fast path "end reached" + result[count++] = id; - return result; + if(count === limit){ + + // fast path "end reached" + + return result; + } } } else{ @@ -118,6 +109,8 @@ export function intersect(arrays, limit, suggest) { res = suggest[i]; len = res && res.length; + // TODO apply offset + if(len){ if(count + len >= limit){ diff --git a/src/serialize.js b/src/serialize.js new file mode 100644 index 0000000..b300252 --- /dev/null +++ b/src/serialize.js @@ -0,0 +1,249 @@ +import Index from "./index.js"; +import Document from "./document.js"; +import { create_object } from "./common.js"; + +function async(callback, self, key, index_doc, index, data){ + + setTimeout(function(){ + + const res = callback(key, JSON.stringify(data)); + + // await isn't supported by ES5 + + if(res && res["then"]){ + + res["then"](function(){ + + self.export(callback, self, key, index_doc, index + 1); + }) + } + else{ + + self.export(callback, self, key, index_doc, index + 1); + } + }); +} + +/** + * @this Index + */ + +export function exportIndex(callback, self, field, index_doc, index){ + + let key, data; + + switch(index || (index = 0)){ + + case 0: + + key = "reg"; + + // fastupdate isn't supported by export + + if(this.fastupdate){ + + data = create_object(); + + for(let key in this.register){ + + data[key] = 1; + } + } + else{ + + data = this.register; + } + + break; + + case 1: + + key = "cfg"; + data = { + "doc": 0, + "opt": this.optimize ? 1 : 0 + }; + + break; + + case 2: + + key = "map"; + data = this.map; + break; + + case 3: + + key = "ctx"; + data = this.ctx; + break; + + default: + + return; + } + + async(callback, self || this, field ? field + "." + key : key, index_doc, index, data); + + return true; +} + +/** + * @this Index + */ + +export function importIndex(key, data){ + + if(!data){ + + return; + } + + if(typeof data === "string"){ + + data = JSON.parse(data); + } + + switch(key){ + + case "cfg": + + this.optimize = !!data["opt"]; + break; + + case "reg": + + // fastupdate isn't supported by import + + this.fastupdate = false; + this.register = data; + break; + + case "map": + + this.map = data; + break; + + case "ctx": + + this.ctx = data; + break; + } +} + +/** + * @this Document + */ + +export function exportDocument(callback, self, field, index_doc, index){ + + index || (index = 0); + index_doc || (index_doc = 0); + + if(index_doc < this.field.length){ + + const field = this.field[index_doc]; + const idx = this.index[field]; + + self = this; + + setTimeout(function(){ + + if(!idx.export(callback, self, index ? field.replace(":", "-") : "", index_doc, index++)){ + + index_doc++; + index = 1; + + self.export(callback, self, field, index_doc, index); + } + }); + } + else{ + + let key, data; + + switch(index){ + + case 1: + + key = "tag"; + data = this.tagindex; + break; + + case 2: + + key = "store"; + data = this.store; + break; + + // case 3: + // + // key = "reg"; + // data = this.register; + // break; + + default: + + return; + } + + async(callback, this, key, index_doc, index, data); + } +} + +/** + * @this Document + */ + +export function importDocument(key, data){ + + if(!data){ + + return; + } + + if(typeof data === "string"){ + + data = JSON.parse(data); + } + + switch(key){ + + case "tag": + + this.tagindex = data; + break; + + case "reg": + + // fastupdate isn't supported by import + + this.fastupdate = false; + this.register = data; + + for(let i = 0, index; i < this.field.length; i++){ + + index = this.index[this.field[i]]; + index.register = data; + index.fastupdate = false; + } + + break; + + case "store": + + this.store = data; + break; + + default: + + key = key.split("."); + const field = key[0]; + key = key[1]; + + if(field && key){ + + this.index[field].import(key, data); + } + } +} diff --git a/src/webpack.js b/src/webpack.js index b0204b1..5b5f4d9 100644 --- a/src/webpack.js +++ b/src/webpack.js @@ -1,4 +1,4 @@ -import { SUPPORT_ASYNC, SUPPORT_DOCUMENT, SUPPORT_CACHE } from "./config.js"; +import { SUPPORT_ASYNC, SUPPORT_DOCUMENT, SUPPORT_CACHE, SUPPORT_SERIALIZE } from "./config.js"; import Document from "./document.js"; import Index from "./index.js"; import { registerCharset, registerLanguage } from "./global.js"; @@ -40,6 +40,15 @@ if(SUPPORT_ASYNC){ /** @export */ Index.prototype.removeAsync; } +if(SUPPORT_SERIALIZE){ + +/** @export */ Index.prototype.export; +/** @export */ Index.prototype.import; + +/** @export */ Document.prototype.export; +/** @export */ Document.prototype.import; +} + window["FlexSearch"] = { "Index": Index,