What is what I call "fuzzy" or "loose" search ?
This is a great feature that let you retrieve results that partly match with your request terms.
1. Choose your champion
First we need a model on which you want to perform the search.
For me, this will be my Schema.org Types. They are semantic objects that represent concepts, like : Shoe store, Product, Organizations, ...
2. Create an api route
Add a new route with a search
method:
// routes/api.php
use Illuminate\Http\Request;
Route::get('type/search/{search?}', 'TypeController@search');
This route will be able to match routes like:
http://localhost:8000/api/type/search/acco
http://localhost:8000/api/type/search/accomodation
http://localhost:8000/api/type/search/store
http://localhost:8000/api/type/search/
- ...
The interogation mark in {search?}
means this parameter is not required. So you might encounter a valid API call like:
http://localhost:8000/api/type/search
3. Create a controller (if you did not yet)
If you do not have a TypeController
yet, run this command to get up and running:
php artisan make:controller TypeController
You will find you controller on app/Http/Controllers/TypeController.php
4. Add the logic on your controller
// app/Http/Controllers/TypeController.php
namespace App\Http\Controllers;
use App\Type;
use Illuminate\Http\Request;;
class TypeController extends Controller {
public function search(Request $request, $search = "") {
if ($request->wantsJson()) {
return response()->json(Type::search($search));
} else {
abort(403);
}
}
}
Here we are just saying:
If the request have been initiated using AJAX, return the result of the static method Type::search()
.
Else, it must have been the user browsing the route http://localhost:8000/api/type/search
manually on his browser, so display a 403 page.
5. The search logic
Write the search method on your Type
model:
// app/Type.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Type extends Model {
protected $table = "type";
protected $primaryKey = "id";
public static function search(string $search) {
$columns = ["id", "name", "partOf", "comment"];
// If the search is empty, return everything
if (empty(trim($search))) {
return static::select($columns)->get();
}
// If the search contains something, we perform the fuzzy search
else {
$fuzzySearch = implode("%", str_split($search)); // e.g. test -> t%e%s%t
$fuzzySearch = "%$fuzzySearch%"; // test -> %t%e%s%t%s%
return static::select($columns)->where("name", "like", $fuzzySearch)->get();
}
}
}
So the trick here is to use the LIKE
SQL operator to do this.
6. Profit $$$
I am using the Insomnia client app to check that my fuzzy search is working.
Do not forget to add the header Accept: application/json
to your request.
Hack it
One improvement would be to allow spaces in the search, so that routes like:
http://localhost:8000/api/type/search/acc+o
http://localhost:8000/api/type/search/shoe s tore
Will still return results.
Just change this line in your Type model search
method:
// app/Type.php
// $fuzzySearch = implode("%", str_split($search));
$fuzzySearch = implode("%", str_split(str_replace(" ", "", $search)));
Another hack you could make is to add several columns to the search using a ->orWhere("column2", "like", $fuzzySearch)
. You can find orWhere
on the dedicated Laravel documentation.
In term of performance, if you are dealing with bunch of data, this will not fit your needs. That is why services like Algolia Search exist.
If you do not have the required budget, you could still be using the MATCH
SQL operator (the keyword name might vary depending the database engine you choose). I found a pretty clean article explaining how to set this up using Laravel for the folks that are seeking a free faster alternative to this fuzzy search here if you do not fear some additional changes on your database schema.
Conclusion
I think this trick can let you offer your user some great search experience, to bring them more results items, requiring a few effort.
I would also be curious to see if my dear Laravelers have something else under the hat to bring fuzzy search to their users. Let me know in the comment.
Bye now, happy coding :)
Top comments (0)