Developer notes
Overview · Installation · Configuration · Usage · FAQ
The add-on keeps its own inverted index in the store database (no external service):
| Table | Contents |
|---|---|
?:kv_ils_objects |
One row per object and language: type (P product, C category, B brand variant, G page, V vendor), id, storefront/vendor, parent product, status, usergroups, title, subtitle, code, normalised title and code, popularity |
?:kv_ils_words |
Normalised words per language with length and document frequency |
?:kv_ils_postings |
Word → object with the summed field weight |
?:kv_ils_grams |
Padded trigrams of every word (typo candidates) |
?:kv_ils_synonyms, ?:kv_ils_stopwords |
Synonym groups and stop words per language |
?:kv_ils_cache |
Suggestion answers (key, JSON, expiry) |
?:kv_ils_meta |
Index revision, build state and run marks (never ?:storage_data) |
?:kv_ils_queries, ?:kv_ils_clicks |
Daily analytics per storefront, language and phrase |
?:kv_ils_rate |
Hourly per-IP counters of the tracking endpoint (salted hash, expire after 2 hours) |
Normalisation: lowercase, accents and special letters folded (é → e, ß → ss, ı → i), separators split words, and hyphenated or dotted groups are also kept joined (T-Shirt → t, shirt, tshirt; USB-C → usbc). Product codes are also indexed without separators.
Field weights: name 10, product code 12, brand 6, categories 4, features 3, search words and meta keywords 3, descriptions 1 (optional). A word that appears in several fields gets the sum (capped at 40).
Upkeep: hooks re-index single objects at once; Builder::step() rebuilds in batches of 200 within a time budget (admin progress loop, --full=Y cron); Builder::update() picks up products by products.updated_timestamp and removes deleted objects (cron, “Update changed products”). A rebuild replaces objects in place and drops stale ones at the end, so the index stays usable. Every change bumps the index revision, which is part of the answer cache key.
Ranking
Section titled “Ranking”For each query word: exact word (quality 1.0), longer words starting with it (0.6–0.9 by length ratio), synonyms (0.9) and, only when the word is unknown, typo candidates: words sharing padded trigrams, verified with the optimal string alignment distance (1 typo for 4–7 letters, 2 for 8+; swapped letters count as one; the last word of a dropdown query is also compared as a prefix). A word scores quality × posting weight per object; an object needs every word (or, when nothing matches all, all but one, with at least one word matched without a typo, × 0.7). Bonuses: exact product code +100, code prefix +20, title equal / starting with / containing the query +15 / +8 / +4, product popularity up to +4 (log scale), category/brand/vendor size up to +3.
On a catalog of 10,000 products (29,500 words, 95,000 postings) a dropdown query takes about 3 ms (p95 6 ms) in the engine; the visibility check and prices of the shown products add a constant 30–40 ms.
Storefront
Section titled “Storefront”index:scriptspost hook printsTygh.kv_ils(endpoint URLs, language, currency, minimum length, texts) andjs/addons/kv_instant_live_search/func.js. The output is identical for every visitor (full page cache safe). The script attaches to everyform[name=search_form] input[name=q].kv_instant_live_search.suggest(GETq,lang,cur): JSON{q, corrected, sections:[{type, items}], popular, fallback, all_url}. Products pass CS-Cart’s own visibility (fn_get_productswith the candidate ids) and get prices with promotions (fn_gather_additional_products_data) for the shown products only. Answers are cached in?:kv_ils_cacheundermd5(query, language, currency, storefront, usergroup set, index revision, settings revision, inventory settings). Guests’ default context is sent withCache-Control: public, max-age=60; any other usergroup context withprivate, max-age=60, so customer-group prices never reach shared caches.Server-Timingreports the phases. The endpoint never writes the session.kv_instant_live_search.track(GETe=ssearch,ddropdown search,cclick;q,nresults,t/idclicked object): 204,no-store, max 300 events per IP and hour.- Results page:
get_products_prereplaces the core LIKE search (q) with the ranked ids for storefront calls withsearch_performed(up to 1,000 ids, variation and vendor-offer children add their parent);get_productsaddsproducts.product_id IN (...)and, unless the visitor chose another sorting,FIELD(products.product_id, ...)as thekv_relevancesorting;get_products_postrestoresq. Filters, pagination and other sortings stay core.products.post.phpassigns the typo note and the no-results fallback; templates use the hooksproducts:search_results_mainbox_titleandproducts:search_results_no_matching_found.
Hooks used
Section titled “Hooks used”get_products_pre, get_products, get_products_post, products_sorting, dispatch_before_display, update_product_post, delete_product_post, update_category_post, delete_category_post, update_page_post, delete_page, update_company, delete_company, tools_change_status, update_product_feature_post, delete_product_feature (identical in 4.17.2 and 4.21.2).
php /path/to/store/admin.php --dispatch=kv_instant_live_search.cron # update changed products, clean upphp /path/to/store/admin.php --dispatch=kv_instant_live_search.cron --full=Y # full rebuildThe command prints a JSON summary.
Licence gate
Section titled “Licence gate”fn_kv_instant_live_search_is_licensed() (Config::isActive(): add-on active, Enable instant search on, License\Client::isActive()) gates the storefront configuration, the suggest and track endpoints and the results-page ranking. When it is off the storefront uses the standard CS-Cart search; the admin page and the index upkeep keep working.
File map
Section titled “File map”| Path | Purpose |
|---|---|
app/addons/kv_instant_live_search/addon.xml |
Settings, tables |
init.php, func.php |
Hooks, storefront configuration, install build, fn_kv_instant_live_search_is_licensed() |
Tygh/Addons/KvInstantLiveSearch/Text.php |
Normalisation, words, trigrams, edit distance |
Indexer.php, Builder.php |
Documents, index writes, full rebuild in steps, incremental update |
Engine.php, Dictionary.php |
Query matching and ranking, synonyms and stop words |
Suggest.php, ResultsPage.php |
Suggest endpoint with cache; results page integration |
Analytics.php, Config.php, Meta.php |
Analytics, settings and gate, key/value marks |
License/, controllers/backend/kv_instant_live_search_license.php |
License check (generated) |
Upgrade/Synchronizer.php |
Self-healing upgrades (generated) |
controllers/frontend/kv_instant_live_search.php, products.post.php |
Suggest and track endpoints, results page data |
controllers/backend/kv_instant_live_search.php |
Admin page, rebuild steps, synonyms, analytics, cron |
schemas/ |
Menu, permissions (vendors have no access) |
var/themes_repository/responsive/templates/addons/kv_instant_live_search/ |
Script/config, results page hooks |
js/addons/kv_instant_live_search/func.js, backend.js |
Dropdown (ARIA combobox, no external libraries); admin progress loop |