ashiqfardus/laravel-fuzzy-search
Installation:
composer require ashiqfardus/laravel-fuzzy-search
No publisher or config required—package auto-discovers.
First Query:
use AshiqFardus\LaravelFuzzySearch\Facades\FuzzySearch;
$results = FuzzySearch::query('users')
->where('name', 'like', 'john')
->fuzzy('name', 'joh')
->get();
Key: Use fuzzy() alongside Eloquent/Query Builder methods.
First Use Case: Implement a search bar for a product catalog:
$products = Product::query()
->fuzzy('name', request('q'))
->orFuzzy('description', request('q'))
->limit(10)
->get();
FuzzySearch for fluent queries; DB::fuzzy() for raw queries.Eloquent Integration:
// Basic fuzzy search
$users = User::fuzzy('email', 'jane.doe@example')->get();
// Combine with other clauses
$activeUsers = User::where('active', true)
->fuzzy('name', 'john')
->orderBy('name')
->get();
Query Builder Integration:
$results = DB::table('products')
->fuzzy('title', 'wireless headphones')
->where('price', '<', 100)
->get();
Multi-Field Search:
$search = FuzzySearch::query('posts')
->fuzzy('title', 'laravel')
->orFuzzy('body', 'eloquent')
->get();
Dynamic Search (API/Forms):
// In a controller
$query = User::query();
if ($searchTerm = request('search')) {
$query->fuzzy('name', $searchTerm)->orFuzzy('email', $searchTerm);
}
return $query->get();
Indexing: Use fuzzyIndex() for pre-computed columns (e.g., name_index):
$users = User::fuzzyIndex('name_index', 'joh')->get();
Tip: Add a fuzzy_index column via migration for static data.
Algorithm Selection:
// Use 'levenshtein' for strict matches, 'soundex' for phonetic
$results = User::fuzzy('name', 'john', 'soundex')->get();
Default: 'levenshtein' (configurable in config/fuzzy-search.php).
Pagination:
$results = User::fuzzy('name', 'joh')->paginate(10);
Custom Algorithms: Extend via service provider:
// app/Providers/FuzzySearchServiceProvider.php
public function register()
{
FuzzySearch::extend('custom', function ($query, $column, $term, $algorithm) {
// Implement custom logic
});
}
Use case: Domain-specific scoring (e.g., prioritize "Apple" over "apple").
Full-Text + Fuzzy Hybrid:
$results = Product::where('category', 'electronics')
->whereFulltext('name', 'wireless')
->fuzzy('brand', 'sony')
->get();
Real-Time Search (Live Search):
// Frontend (Vue/React)
const debouncedSearch = _.debounce(async (term) => {
const results = await axios.get(`/api/search?q=${term}`);
// Update UI
}, 300);
Backend:
Route::get('/api/search', function () {
return User::fuzzy('name', request('q'))->limit(5)->get();
});
Case Sensitivity:
->fuzzy('column', 'term', 'levenshtein', true) (4th param for case-insensitive).$table->string('name_lower')->nullable();
Then search on name_lower.Performance with Large Datasets:
fuzzy_index column (pre-computed hash).->limit() aggressively.$results = Cache::remember("fuzzy_search_{$term}", now()->addHours(1), function () use ($term) {
return User::fuzzy('name', $term)->get();
});
Algorithm Mismatch:
'soundex' fails for non-English names (e.g., "Müller").'levenshtein' or 'metaphone' for broader coverage.Reserved Keywords:
orFuzzy conflicts with Laravel’s orWhere.->orFuzzy() explicitly or alias:
$query->macro('orFuzzy', function ($column, $term) {
return $this->orWhere(function ($q) use ($column, $term) {
$q->fuzzy($column, $term);
});
});
Query Inspection: Enable SQL logging to verify generated queries:
DB::enableQueryLog();
$results = User::fuzzy('name', 'joh')->get();
dd(DB::getQueryLog());
Algorithm Validation: Test algorithms with edge cases:
// Test 'soundex' with homophones
$results = User::fuzzy('name', 'c', 'soundex')->get(); // Matches "C", "K", "Q"
Index Utilization:
Check if fuzzyIndex is used:
// Should generate: `WHERE fuzzy_index LIKE '%hash%'`
$results = User::fuzzyIndex('name_index', 'joh')->get();
Custom Scoring: Override the default scoring logic in a service provider:
FuzzySearch::macro('customScore', function ($query, $column, $term) {
return $query->whereRaw("SOUNDEX($column) = SOUNDEX('$term')");
});
Database-Specific Optimizations:
LIKE with wildcards for partial matches:
$query->where($column, 'LIKE', "%{$term}%");
pg_trgm for faster fuzzy matches:
$query->where("similarity($column, '$term') > 0.5");
Search Analytics: Track search terms and results for UX improvements:
event(new SearchPerformed(
auth()->id(),
request('q'),
$results->count()
));
config/fuzzy-search.php:
'default_algorithm' => 'metaphone', // or 'levenshtein', 'soundex'
'case_insensitive' => env('FUZZY_CASE_INSENSITIVE', false),
password):
'ignored_columns' => ['password', 'remember_token'],
Combine with Laravel Scout: Use fuzzy search for backend fallbacks:
if (request('q')) {
$results = Product::search(request('q'))->get();
if ($results->isEmpty()) {
$results = Product::fuzzy('name', request('q'))->get();
}
}
Typeahead Autocomplete: Limit results to top matches:
$suggestions = User::fuzzy('name', 'jo')
->orderByRaw('LENGTH(name) - LENGTH(REPLACE(name, ?, ''))') // Prioritize shorter matches
->limit(5)
->pl
How can I help you explore Laravel packages today?