Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Manticore Eloquent Laravel Package

renatomaldonado/laravel-manticore-eloquent

Manticore Eloquent integrates Manticore Search with Laravel models, letting you define searchable Eloquent-style models, sync data, and run fast full-text and attribute queries using familiar Laravel ORM patterns.

View on GitHub
Deep Wiki
Context7

Getting Started

This release lands on a Manticore-backed Eloquent driver, so the first thing to confirm is that your model extends ManticoreModel and that your config/database.php has a manticore connection pointing at your server (the README examples assume Article::manticore() is available via a scope/trait — check the service provider registration matches what the README shows for your version).

If you already have vector search working, the first thing to try is the new document-id form of knn(), because it is the use case most people were hand-rolling with raw SQL:

Article::manticore()->knn('embedding', $article->id, k: 10)->get();

That returns neighbours and never the source row, which is exactly "more like this article" and saves you filtering the source id out of the results yourself.

If you are new to vectors on this driver, start with VectorCast rather than with knn(). Previously you could not write a vector through the query builder at all — Manticore requires a bare tuple literal (0.1, 0.2, 0.3) and no bound parameter can express that, so inserts meant raw SQL. Now:

use ManticoreEloquent\Eloquent\Casts\VectorCast;

class Article extends ManticoreModel
{
    protected $casts = ['embedding' => VectorCast::class];
}

Article::create(['embedding' => [0.1, 0.2, 0.3]]);

Where to look first in the README: the document-id form, the option block, VectorCast, and the two live-server gotchas (cosine normalisation and UPDATE-on-KNN-column). Those gotchas are the difference between a demo that works and a feature that survives production.

Implementation Patterns

Similar-articles / recommendation block. The document-id form is the day-to-day pattern: take an id from the request, scope it to the tenant, and let Manticore find neighbours. Pair it with your normal Eloquent scopes — the driver composes with where() fine.

Tuning recall per query. The 4th argument is now the whole option block, matching what Manticore actually parses:

Article::manticore()
    ->knn('embedding', $queryVector, k: 10, ef: ['ef' => 2000, 'rescore' => true])
    ->get();

Because there is no allow-list of option names, you can adopt new server-side KNN options without waiting for a package release — pass them straight through. Treat that as a feature for internal/profiling work and as a review checkpoint for anything user-driven.

Search UI wiring. Keep the vector, k, and the option block in a single form request / DTO so k and ef are validated as integers and the options array is built from a known shape. The package validates the shape of options, not their semantics — a valid integer that means something silly to your index still gets sent.

Mixing text and KNN. The usual ranking pipeline — a match/full-text filter to shrink the candidate set, then knn() for ordering — still applies, and the option block is where you put rescore when you want the text score to re-rank the vector candidates.

Vector writes. Put VectorCast on every embedding column and forget about the tuple syntax entirely. Reads come back as PHP arrays, so your application code never sees the string form.

DB::raw() for function-call options. If you set a ranker of the form expr('sum(lcs)'), that now must be wrapped:

->option('ranker', DB::raw("expr('sum(lcs)')"))

Bare keywords (sph04, kbuffer), numbers, bools, arrays like field_weights, and quoted literals (idf='plain,tfidf_unnormalized', comment='…') are unchanged. Sweep your codebase for ->option( calls that pass function-looking strings.

Gotchas and Tips

This release is breaking in two places, and one is silent if you skip the changelog. The visible one: ->option() with a function-call string now throws InvalidArgumentException — wrap in DB::raw(). The quiet one: if you extended the package, knn() and whereKnn() changed signature and the wheres entry key ef became options. Any subclass overriding those, or any code inspecting the wheres array, needs updating even though nothing throws until runtime.

The old positional form never worked. ->knn($column, $vector, $k, $ef) used to emit knn(col, k, (v), 2000), which Manticore rejects with a syntax error. So if you had a call site that "worked" — it didn't; you probably had it commented out or behind a flag. The fix needs no caller change, but expect previously-failing tests to start passing and look at them rather than assuming they're noise.

Floats must be PHP floats. 'oversampling' => 3.0, not 3. Manticore rejects an integral literal for a float-only option, and PHP will happily hand the package an int. Cast at the boundary: (float) $request->input('oversampling').

Null means unset now. A null option value is dropped instead of being sent as 0. If you were relying on null producing a zero — unlikely, but check any generated option arrays — behaviour changed.

Cosine columns don't round-trip. On a cosine-normalised column Manticore stores the unit vector, so ->embedding after a read is the normalised version, not what you wrote. Don't assert equality against the input in tests; assert direction/normalised equivalence, or use a non-cosine space in fixtures.

You cannot UPDATE a KNN-indexed column. Manticore refuses it. Use replace() to change a vector. Any mass-update or "re-embed everything" job needs rewriting as delete-and-replace; a ->update(['embedding' => …]) will fail at the server, not in PHP.

Option values are validated by shape, not bound. Option names and values are interpolated — Manticore's OPTION and knn() blocks take bare keywords, not parameters, so they can never be bound. The release closes the obvious hole (a name must be an identifier; a value must be a number, bool, bare word, or self-contained quoted literal), but the correct habit remains: never build the option name from request input, and construct option values from validated/typed sources. Shape validation stops fragment escape, not semantic abuse.

Debugging: dump the generated SQL before blaming the driver. The failure modes here are all server-side parse errors (syntax error, unexpected integer, expecting '{') that tell you exactly which clause is malformed — the option block is the first place to look. Verified against Manticore 17.5.1; if you are on an older server, some pass-through KNN options will simply be unknown to it.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr