webx-ui / module-catalog-manticore
Manticore Search as the engine of the WebX UI catalogue: a table per language with the morphology of every language of the site, facets and counts in one round trip, rebuilds swapped in whole, and the database to fall back on.
Package info
github.com/webx-ui/module-catalog-manticore
pkg:composer/webx-ui/module-catalog-manticore
Requires
- php: ^8.4
- guzzlehttp/guzzle: ^7.8 || ^8.0
- illuminate/contracts: ^13.0
- illuminate/http: ^13.0
- illuminate/support: ^13.0
- webx-ui/module-catalog: ^0.56.0
Requires (Dev)
- orchestra/testbench: ^11.0
- phpunit/phpunit: ^12.0 || ^13.0
- webx-ui/module-catalog-brands: ^0.56.0
- webx-ui/module-catalog-labels: ^0.56.0
- webx-ui/module-catalog-stock: ^0.56.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Manticore Search as the engine of the catalogue of the WebX UI admin panel — for catalogues the database engine no longer carries (more than a couple of thousand products). Category pages, filters with their counts, the search and the panel's product list are answered by Manticore; the product page itself never is.
Requirements
- PHP 8.4+, Laravel 13
webx-ui/module-catalogand what it requires- A Manticore Search server (29 or later) reachable over its HTTP JSON API. The package does not install or configure it, and one server may serve several projects.
Install
composer require webx-ui/module-catalog-manticore
WEBX_CATALOG_ENGINE=manticore MANTICORE_HOST=127.0.0.1 MANTICORE_PORT=9308 MANTICORE_TABLE_PREFIX=my_shop
php artisan webx:catalog:index --rebuild
The prefix is required and has no default: two copies of one site on one server would otherwise
write into each other's tables. It is [a-z0-9_]; the tables are
{prefix}_catalog_products_{locale}, and the package touches nothing else on the server.
php artisan webx:doctor says when the prefix is missing, when it begins somebody else's tables,
when the server does not answer and when a table is out of date.
From there the core's queue keeps the index current: saving a product marks it, and
webx:catalog:index on the schedule writes the marked ones every minute.
A table per language
Every language of the site has a table, and every table holds every language: its own in the main
text columns, weighed higher, and the others in other_languages. A product is found by a word in
any language of the site from a page in any language, and its own language ranks first. A product
without a translation is indexed with the text of the main language, as the storefront shows it.
The morphology of a table is that of every language of the site, its own first
(webx-catalog-manticore.morphology); a language not named there is indexed without morphology.
The beginning of a word is always searched.
The search
A search is its words and their beginnings, in any language of the site. The codes of a product —
the article number, the barcode, the external id — are searched as written and by any part of their
letters and digits: at1234, 34/5 and AT-1234/56 all find AT-1234/56. Whatever the reader
typed is a character, never an operator of the query language. The product whose code the search
is comes first, and when it is the only one on the site the storefront goes straight to its card.
A search that finds nothing gets a second pass: as typed with another keyboard layout of the site's
languages (xt[jk is чехол; webx-catalog-manticore.layouts), then each word as the index's
dictionary spells it (CALL QSUGGEST). The page says «Showing results for …» with a link to the
words as typed (?typed=1); the lines are webx-catalog::storefront.search-corrected and
search-instead, the view webx-catalog::search-corrected. The panel's list does the same.
Rebuilding
webx:catalog:index --rebuild fills {table}_next beside each live table and swaps it in when it
is whole; the storefront reads the old tables meanwhile. A rebuild is needed when Manticore is
connected to a catalogue that already has products, when the schema changes (a language added, a
morphology changed, a new version of a module that writes into the index), or when the server lost
its data. webx:doctor reports a table that is out of date; when to rebuild is yours to choose.
When the server does not answer
The failure is remembered for down_for seconds (30), so nobody waits for it twice. Meanwhile the
panel reads the database, and so does a storefront whose catalogue is within
webx-catalog.sql_engine_limit; a larger catalogue answers 503 with Retry-After, on the site's
own layout — header, menu and footer in place (the view webx-catalog-manticore::unavailable,
published with --tag=webx-catalog-manticore-views). Saving a product
never fails because of Manticore: the product waits in the queue.
Config
php artisan vendor:publish --tag=webx-catalog-manticore-config
connect_timeout, timeout, down_for, morphology, min_prefix_len, min_infix_len,
weights, layouts, facet_values, relevance_sample — see the comments in the file.
License
MIT