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

Elasticsearch Search String Parser Laravel Package

spatie/elasticsearch-search-string-parser

Convert custom search strings like "foo bar status:active @john.doe" into ElasticSearch requests. Add directives via regex and the spatie/elasticsearch-query-builder, with grouping and autocomplete suggestions.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This package is a thin parsing layer, not a search platform. Its responsibility is narrow and well-bounded: take a user-supplied string, dispatch regex-matched fragments to developer-defined PatternDirective classes, strip those fragments, and hand the remainder to a single BaseDirective; then execute the assembled query through spatie/elasticsearch-query-builder and return a SearchResults object with hits plus directive suggestions. It fits cleanly where an application already has (or is committing to) Elasticsearch 8 as its query backend and wants a key:value search grammar without building a tokenizer/parser. It does not fit if the team expects faceted-search infrastructure, relevance tuning, indexing strategy, or pagination semantics to come out of the box — none of that is in scope.

Integration feasibility. Low-to-moderate effort, high clarity. Installation is one Composer require; there is no service provider, no published config, no Artisan commands, no migrations. Laravel "support" in this package is strictly Composer version constraints (Laravel 9 through 13 tracked in the changelog), not framework integration — so all wiring is explicit application code: construct the ES client, register directives, call ->search(), hydrate the returned _id list against Eloquent or your read model. That explicitness is a feature for a TPM: there is no hidden framework magic to reason about during upgrades.

Technical risk.

  • Documentation risk is the largest single item. The README's ## Usage block is an unedited Spatie skeleton stub (echoPhrase('Hello, Spatie!')) and has nothing to do with the package. The only load-bearing documentation is the "How it works: directives" section. Abstract directive method signatures (getPattern, the apply hook, the suggestion method) are undocumented outside src/. Budget engineering time for reading source, not docs.
  • Two-package dependency. Every directive you write is really a spatie/elasticsearch-query-builder call. The parser only routes strings; clause shapes, boosting, filters, and aggregations come from the builder. Adopting this package means adopting and understanding both. Treat that as a scope increase in the design review.
  • Elasticsearch major coupling. ^2.0 requires ES8 and the elasticsearch/elasticsearch 8.x client; ES7 clusters require the 1.x line. A mismatch surfaces as a client-layer error that reads nothing like a parser bug — confirm cluster version before pinning.
  • Low adoption signal. 51 stars, zero dependents, a single maintainer organization. There is no downstream corpus proving edge-case behavior. Treat the package as "maintainer-owned source you happen to import," not as battle-tested infrastructure.
  • Regex on user input. Pattern directives match attacker-controllable strings, and the parser loops applying directives until no further matches. Greedy patterns plus unbounded input is a real ReDoS and CPU-amplification surface. Input length caps and anchored, non-greedy patterns should be a merge requirement, not a follow-up.
  • Thinness cuts both ways. The parsing loop is small enough to reimplement in a sprint. The value you are buying is the convention and the query-builder coupling, not irreplaceable logic — which also means the exit cost is low if the dependency sours.

Key questions for the team.

  1. Is the target screen internal (support console, admin list, CRM) or public-facing? Scope the first release to internal only.
  2. Which ES major is the target cluster on, and which package major does that pin us to?
  3. Do we accept ownership of spatie/elasticsearch-query-builder semantics, or do we need a wrapper to insulate our directives from it?
  4. Who owns the directive registry, and what is the review process for adding a new directive (regex safety, ordering, suggestion copy)?
  5. What are our input length limits and rate limits on the endpoint that accepts the raw string?
  6. Is result hydration (ES _id → application model, preserving relevance order) our responsibility? It is; decide the pattern before the first PR.

Integration Approach

Stack fit. Strong for a Laravel application on PHP 8.x with Elasticsearch 8 already in the stack. The package is framework-agnostic, so it composes without fighting Laravel: directives are plain classes (autowirable, testable), and the surrounding endpoint is a normal controller with a Form Request validating q length and charset. There is no opinion about tenancy, authorization, or index naming — those are ours to enforce, and they should be enforced before the string reaches the parser, not inside directives.

Migration path. Greenfield adoption is trivial. For teams currently doing naive multi_match on a request parameter, the migration is additive and reversible: introduce the parser behind a feature flag on one internal screen, keep the old query path live, and compare result sets on real queries before cutting over. Because directives are our own classes, rollback means disabling a config flag and falling back to the previous query construction — no data migration, no schema change, no reindex. That reversibility is the main argument for trying it.

Compatibility. Pin the major to the cluster: ^2.0 for ES8, 1.x for ES7. Verify the Laravel constraint against the app's current version — the changelog shows sequential Laravel 9→13 support, so an app on an older LTS may be stuck on an older parser tag with correspondingly older tooling. Watch the spatie/elasticsearch-query-builder constraint as a transitive pin; a lock-file bump there can change generated clause shapes without any parser release. Also confirm PHP version alignment: the 2.0 line modernized tooling to PHP 8.5/Pest 4/PHPStan level 5, which implies a fairly current runtime baseline.

Sequencing.

  1. Spike (1–2 days): cluster version confirmation, package pin, one base directive + one pattern directive, hit hydration into an existing model. Success criterion: an internal search box returns correctly ordered, correctly hydrated results.
  2. Design review: directive taxonomy. One directive per user-facing concept (status:, sort:, @user, group_by:); each keeps its regex, apply logic, and suggestion copy in a single file. Register most-specific patterns first — the parser iterates directives in registration order and strips matches as it goes, so a greedy early pattern will eat input intended for later directives.
  3. Hardening: regex review for ReDoS, input length caps at the Form Request, error handling around the ES call, structured logging of the raw query string.
  4. First screen ship (internal), then a second screen to prove the directive abstraction generalizes before exposing the syntax to external users.
  5. Defer grouping/group_by aggregations and suggestion metadata until after the plain filter/search path is stable in production — they are the parts most likely to need bespoke work.

Operational Impact

Maintenance. The steady-state maintenance burden is low but non-zero, and it is mostly ours, not upstream's. Upstream moves slowly and in large steps (the 2.0 line was a major-version jump with a tooling modernization); the practical cadence is "review once or twice a year, expect a breaking bump when the ES client majors." Our recurring cost is the directive registry: every product request for a new filter becomes a class, a regex, an ordering decision, and a test. Plan for that as a small standing line item rather than a one-off build. The documentation gap does not heal itself over time — write an internal ADR capturing directive conventions, because the README will not.

Support. Support surface is the search grammar, not the package. The expensive support tickets are "why did status:active return nothing" — which are index/analyzer/data problems masquerading as parser bugs. Mitigations: expose returned suggestions to the UI (the package supplies them), log the parsed query string alongside the ES request, and keep an internal directive reference doc. Escalation to upstream is effectively not a plan: 51 stars and zero dependents means no community backstop, so assume we debug our own issues from source. The upside is that the source is small enough to read fully.

Scaling. The parser is stateless and CPU-cheap per request under sane input; the bottleneck is Elasticsearch itself, not this package. Two caveats. First, cost scales with directive count × input length because the parser loops over directives repeatedly stripping matches — with a dozen directives and unfiltered long input, this becomes measurable. Bound it with a max-length Form Request rule and a directive count that stays in the single digits per endpoint. Second, the package executes the query directly, so there is no natural seam for caching or for async/deferred execution — if you need result caching or a query gateway, wrap the call site, don't try to extend the parser.

Failure modes.

  • Cluster-version/client mismatch — fails at the client layer with misleading errors; prevented by the initial version check.
  • ReDoS / CPU amplification on a crafted search string — the highest-severity risk and the one most likely to page someone; prevented by anchored non-greedy patterns plus input caps.
  • Greedy pattern shadowing — one directive silently consumes input meant for another, producing wrong-but-not-erroring results; prevented by registration-order discipline and per-directive unit tests.
  • Empty remainder — when only directives are supplied and no free text survives, the base directive receives an empty string; behavior is directive-defined and must be tested, or users get zero results on a valid-looking query.
  • Elasticsearch unavailability / timeouts — unhandled by the package; needs explicit try/catch, a degraded response, and a circuit breaker at the controller.
  • Hydration ordering loss — ES returns _ids in relevance order; a naive whereIn re-sorts and silently degrades relevance. This is the most common production bug in this integration pattern and is entirely on us.
  • Transitive dependency drift — an unrelated composer update moves elasticsearch-query-builder and changes clause shapes; mitigated by lock-file discipline and a result-set regression test.

Ramp-up. Fast for anyone comfortable with Elasticsearch query DSL — roughly an afternoon to a working spike, one to two weeks to a hardened internal screen with tests. The learning curve is almost entirely in two places: the query builder's clause semantics (read that README concurrently) and the undocumented directive abstract-class signatures (read src/, trust it over any blog post). Engineers without prior ES experience will need more time, because debugging parser output requires being able to read the generated query. Do not treat this as a shortcut for teams that have not yet internalized Elasticsearch relevance and analysis behavior — the package routes strings, it does not make search quality decisions for you.

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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log