Download the PHP package ashiqfardus/laravel-fuzzy-search without Composer

On this page you can find all versions of the php package ashiqfardus/laravel-fuzzy-search. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-fuzzy-search

Laravel Fuzzy Search

Latest Version on Packagist Total Downloads License PHP Version Laravel Version

A powerful, zero-config fuzzy search package for Laravel with fluent API. Works with all major databases without external services.

Demo: laravel-fuzzy-search-demo - See the package in action!

Documentation: Upgrade v1→v2

Features

Category Features
Core Zero-config search • Fluent API • Eloquent & Query Builder support
Algorithms Multiple fuzzy algorithms • Typo tolerance • Multi-word token search
Scoring Field weighting • Relevance scoring • Prefix boosting • Partial match • Recency boost
Text Processing Stop-word filtering • Synonym support • Language/locale awareness
Internationalization Unicode support • Accent insensitivity • Multi-language
Results Highlighted results • Custom scoring hooks • Debug/explain-score mode
Performance BM25 inverted index • Async indexing (queue) • Redis/cache support
Pagination Stable ranking • Cursor pagination • Offset pagination
Reliability Fallback search strategy • DB-agnostic • Rate-limit friendly • SQL-injection safe
Configuration Config file support • Per-model customization
Developer Tools CLI indexing • Benchmark tools • Built-in test suite • Performance utilities
Smart Search Autocomplete suggestions • "Did you mean" spell correction • Multi-model federation • Search analytics

Table of Contents


Installation

That's it! Zero configuration required. Start searching immediately.

Optionally publish the config file:

If you plan to use the BM25 inverted index (recommended for 10k+ rows), also run:

Upgrading from v1.x? There are breaking changes — result rankings and _score values may shift. Run the scanner to find affected code, then follow the full guide.

→ Full upgrade guide


Quick Start

Zero-Config Search

How auto-detection works: The package automatically detects common column names in this priority order:

If none of these exist, it falls back to the model's $fillable columns.

Manual Column Configuration

You can manually specify which columns to search and their weights:

Fluent API

Eloquent & Query Builder Support


Search Algorithms

Available Algorithms

Algorithm Best For Typo Tolerance Speed
fuzzy General purpose High Fast
levenshtein Strict typo matching Configurable Medium
soundex Phonetic matching (English names) Phonetic Fast
metaphone Phonetic matching (more accurate) Phonetic Fast
trigram Similarity matching High Medium
similar_text Percentage similarity Medium Medium
simple / like Exact substring (LIKE) None Fastest

⚠️ metaphone requires one-time setup. Unlike the other algorithms, it searches against a precomputed {column}_metaphone shadow column. Calling using('metaphone') without it throws RuntimeException. Run the three commands shown in Shadow Columns once per searchable column.

Shadow Columns

Most algorithms compute their score on the fly during the SQL query. Metaphone is the exception — PHP's metaphone() function isn't available in SQL, so the package precomputes the phonetic code on every save and stores it in a sibling column.

For a users table with a name column, that means adding a name_metaphone column right next to it. Each row's name_metaphone holds the phonetic code (e.g. StephenSTFN, StevenSTFN, StefanSTFN). At search time, the query is a simple equality check against the precomputed code — fast, no per-row PHP calls.

Setup (one-time per column):

After this, the SearchableObserver keeps name_metaphone in sync automatically on every save() and update().

What gets generated:

Safety guards in the command:

Typo Tolerance

Multi-Word Token Search

In-Memory Mode

Supported methods: search, searchIn, take, skip, withRelevance, get. Any other SearchBuilder method (e.g. extended(), using(), preset(), paginate()) will throw a \BadMethodCallException to prevent silent failures.


Field Weighting & Scoring

Weighted Columns

Relevance Scoring

Prefix Boosting

Partial Match Support

Custom Scoring Hooks

Recency Boost

Boost newer records in search results:

Search Suggestions / Autocomplete

Get autocomplete suggestions based on search term:

"Did You Mean" Spell Correction

Get alternative spellings when search has typos:

Multi-Model Federation Search

Search across multiple models simultaneously:

Search Analytics

Get detailed analytics about your search configuration:


Text Processing

Stop-Word Filtering

Synonym Support

Language / Locale Awareness

Unicode & Accent Insensitivity


Result Presentation

Highlighted Results

Debug / Explain-Score Mode


Performance & Indexing

Async Indexing (Queue Support)

Redis / Cache Support


BM25 Inverted Index

For large tables (10k+ rows), the BM25 inverted index provides ranked, fast results without scanning the full table.

How It Works

The indexing system has two parts:

Part 1 — One-time initial build. Run once after install (or after a schema change):

Part 2 — Automatic incremental updates. After the initial build, every time a model is saved or deleted, the package dispatches a small queue job that re-indexes just that one row. No cron jobs or manual work needed.

The flow when a record is saved:

Database Tables

Table Purpose
fuzzy_index_terms Term dictionary: unique terms + document frequency (used for didYouMean())
fuzzy_index_postings Postings: term → model mapping with term frequency
fuzzy_index_meta BM25 normalization: total docs + avg document length per model
fuzzy_index_documents Per-document length cache for O(1) BM25 scoring

Production Setup

Step 1 — Run migrations:

Step 2 — Enable indexing in config:

Step 3 — Declare searchable columns on your model:

Step 4 — Build the initial index:

Step 5 — Start a queue worker:

Supervisor config (/etc/supervisor/conf.d/fuzzy-search-worker.conf):

For Laravel Horizon (Redis):

Usage

Note: useIndex() is an alias for useInvertedIndex(). The deprecated legacy search_index table from v1 is no longer used.

Limitation: The BM25 inverted index requires integer primary keys. Models with UUID/ULID primary keys are not currently supported — use the standard LIKE or Levenshtein paths for those.

Column weights and BM25: searchIn() weights are respected by the LIKE/Levenshtein scoring paths but are ignored by BM25. BM25 scores by term frequency and inverse document frequency only.

Artisan Commands

BM25 Tuning

Stemming (Optional)

Default: no stemming (NullStemmer). With NullStemmer, running only matches running, not run or ran.

To enable Porter stemming:

Supported languages: English, French, German, Spanish, Italian, Russian, Dutch, Portuguese, Swedish, Danish, Norwegian. You must rebuild the index after changing the stemmer.

Observer Auto-Attach

Adding the Searchable trait automatically registers observers via bootSearchable():

No configuration is required for either observer until you enable those features.

Sync vs Async

async = true (default) async = false
How it works Dispatches IndexModelJob to queue Indexes in the same request, no queue
Request latency Unaffected +~10ms per save
Requires queue worker Yes No
Best for Production apps Tests, local dev, low-traffic apps

For tests, set indexing.async = false so indexing happens synchronously:


Extended Search Syntax

Use Fuse.js-style operators inside your search string for precise control over matching.

Operators

Token Meaning Example
word Substring match (default) john
'word Explicit substring include 'admin
=word Exact equality =John
^word Prefix match ^Doe
word$ Suffix match Sr$
!word Exclude (NOT) !banned
!^word Inverse prefix !^test
!word$ Inverse suffix [email protected]$
\| OR john \| jane
(whitespace) AND (implicit) =John ^Doe
( ... ) Grouping admin (john \| jane)
"phrase" Quoted single token "hello world"

Usage

Limits

Limit Default Config key
Maximum tokens per query 32 query.max_tokens
Maximum nesting depth 16 query.max_depth

Pagination with Extended Syntax

paginate() and cursorPaginate() are not compatible with extended() or searchBoolean() and will throw a BadMethodCallException. simplePaginate() works correctly.

Match Offsets & Blade Directive

Results with ->highlight() enabled include a _matches array:

For safe HTML rendering, use the @fuzzyHighlight Blade directive:

The directive automatically escapes user-supplied content and wraps matches in <mark> tags.


Scout Driver

The Scout engine adapter is bundled in this package and registers automatically when laravel/scout is installed. No separate driver package is required.

Setup

In .env:

Build the index:

Usage

Add both traits to your model:

Relevance Scores

Results include _score (BM25 relevance, higher = more relevant):

Authorization

Scout's default behavior bypasses Eloquent global scopes. Apply them explicitly:

How It Works

The Scout engine wraps the same IndexManager + Bm25Scorer used by Model::search()->useInvertedIndex(). There is no separate index — it reads from the same fuzzy_index_* tables.


Pagination

Stable Ranking

Pagination Methods

Note: paginate() and cursorPaginate() are not compatible with extended() or searchBoolean(). Use simplePaginate() or get() with those.


Reliability & Safety

Fallback Search Strategy

Rate-Limit Friendliness

SQL Injection Safety

All queries use parameterized bindings. Search terms are automatically sanitized.

Exception Handling

Available Exceptions:


Events

FuzzySearchExecuted

Fired after every ->get() or ->paginate() call. Useful for monitoring search latency and volume in production.

Properties:


Configuration

Config File

Config Presets

Presets are predefined search configurations for common use cases. Instead of manually configuring multiple options every time, use a single preset name.

Without preset (verbose):

With preset (clean):

Available Presets

Preset Best For Algorithm Typo Tolerance Features
blog Blog posts, articles fuzzy 2 Stop words, accent-insensitive
ecommerce Product search fuzzy 1 Partial match, no stop words
users User/contact search levenshtein 2 Accent-insensitive
phonetic Name pronunciation soundex 0 Phonetic matching
exact SKUs, codes, IDs simple 0 Partial match only

Preset Configuration Reference

Using Presets

Override Preset Settings

Create Custom Presets

Per-Model Customization


CLI Tools

Indexing Commands

Benchmark & Debug Commands


Performance & Scaling

Algorithm Comparison

Algorithm Speed Typo Tolerance Best For Dataset Size
simple Fastest None Exact matches, SKUs Any size
fuzzy Very Fast High General purpose < 100K rows
soundex Very Fast Phonetic Name searches < 100K rows
trigram Fast Very High Similarity matching < 50K rows
levenshtein Medium Configurable Precise typo matching < 50K rows
BM25 index Fast at scale Via LIKE fallback Large tables, ranked results 10K+ rows

Measured Latency (100k-row MySQL 8.0 dataset)

Numbers measured on the live demo (commodity VPS, warm cache). Run php artisan demo:seed in the demo project to seed the same dataset.

Search path Median latency Notes
LIKE (using('simple')) ~8 ms Full table scan
Levenshtein (using('levenshtein')) ~45 ms PHP re-score over 1,000 SQL candidates
BM25 inverted index (useInvertedIndex()) ~12 ms Three parameterised SQL queries + PHP BM25 scoring
Extended syntax (->extended()) ~15 ms Includes AST compilation and multi-operator SQL generation

At scale: The BM25 path uses an indexed term lookup — query time grows with the number of matching postings, not total row count. A well-maintained 1M-row index returns results in the same ~12–20 ms window as the 100k baseline.

When to Use BM25 vs LIKE

Use BM25 (useInvertedIndex()) when:

Use LIKE / fuzzy when:

max_candidates Tuning

For the LIKE/Levenshtein paths, SQL candidates are fetched then re-scored in PHP. The candidate set size is controlled by max_candidates (default: 1000). Lower this on large tables to reduce memory usage:

Recommended Optimizations

Key tips:

  1. Use the BM25 index for tables with 10k+ rows
  2. Enable caching for repeated searches
  3. Limit columns — only search relevant fields
  4. Use simple algorithm when typo tolerance isn't needed
  5. Set max_candidates to prevent excessive memory usage on large tables
  6. Use take() to cap result sets
  7. Eager load relationships to avoid N+1 queries

Scaling Recommendations

Records Recommended Strategy Expected Query Time
< 50K Default (no optimization) < 50ms
50K - 100K Add DB indexes + cache < 100ms
100K - 500K BM25 index + cache < 150ms
500K - 1M BM25 index + partitioning + cache < 200ms
1M - 10M BM25 + read replicas + tiered cache < 300ms
> 10M Consider Meilisearch / Typesense

Algorithm × Database Compatibility

This table shows what each algorithm does at the SQL level on each supported database. "Native" = the database's own function. "Pattern fallback" = PHP generates LIKE patterns.

Algorithm MySQL 8 MariaDB 10.6 PostgreSQL 14 SQLite SQL Server
simple / like LIKE '%term%' LIKE '%term%' ILIKE '%term%' LIKE '%term%' LOWER() LIKE
fuzzy LIKE pattern set (typo patterns, transpositions) LIKE pattern set ILIKE pattern set LIKE pattern set LIKE pattern set
levenshtein Native LEVENSHTEIN() UDF if use_native_functions=true, else pattern set Pattern set similarity() via pg_trgm if use_native_functions=true, else pattern set Pattern set Pattern set
trigram LIKE pattern set LIKE pattern set Native similarity() via pg_trgm if use_native_functions=true LIKE pattern set LIKE pattern set
soundex Native SOUNDEX() — always on, applied to first or last word Native SOUNDEX() — always on Native SOUNDEX() via fuzzystrmatch if use_native_functions=true, else pattern fallback Pattern fallback Pattern fallback
metaphone Shadow column {col}_metaphone + exact = match Shadow column Shadow column Shadow column Shadow column
similar_text LIKE '%term%' (SQL); similar_text() scores in PHP after fetch Same ILIKE '%term%'; PHP scores Same Same

Notes

PHP-Side Scoring

Regardless of algorithm, after SQL candidates are fetched:

  1. similar_text() and levenshtein() run in PHP on each candidate.
  2. Results are re-sorted by the combined PHP score (higher = better).
  3. limit/offset is applied on the PHP-sorted collection (not in SQL).

Top-N results are always the most relevant N from the candidate set (not just the first N SQL rows). Candidate set size is controlled by max_candidates (default: 1000).

Pagination note: paginate() and simplePaginate() use DB-level pagination and score within the current page only. For globally-ranked pagination across all pages, use the BM25 inverted index.


Testing


Requirements


License

MIT License. See LICENSE for more information.

Credits

Contributing

Contributions are welcome! Please see CONTRIBUTING for details.


All versions of laravel-fuzzy-search with dependencies

PHP Build Version
Package Version
Requires php Version ^8.1|^8.2|^8.3|^8.4
illuminate/database Version ^9.0|^10.0|^11.0|^12.0|^13.0
illuminate/support Version ^9.0|^10.0|^11.0|^12.0|^13.0
illuminate/console Version ^9.0|^10.0|^11.0|^12.0|^13.0
illuminate/queue Version ^9.0|^10.0|^11.0|^12.0|^13.0
illuminate/bus Version ^9.0|^10.0|^11.0|^12.0|^13.0
symfony/finder Version ^6.0|^7.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ashiqfardus/laravel-fuzzy-search contains the following files

Loading the files please wait ...