Unmaintained: Laravel Searchy makes user driven searching easy with fuzzy search, basic string matching and more to come!

Last update: Jun 20, 2022

!! UNMAINTAINED !! This package is no longer maintained

Please see Issue #117

Here are some links to alternatives that you may be able to use (I do not guarantee the suitability or the quality of these projects, please ensure you do your own due dilligence in ensuring they meet your requirements):

  • TODO

Laravel 5+ Searchy

Database Searching Made Easy

Searchy is an; easy-to-use, light-weight, MySQL only, Laravel package that makes running user driven searches on data in your models simple and effective. It uses pseudo fuzzy searching and other weighted mechanics depending on the search driver that you have enabled. It requires no other software installed on your server (so can be a little slower than dedicated search programs) but can be set up and ready to go in minutes.

!! Laravel 4 !!

Looking for Laravel 4 compatible Searchy? Checkout the 1.0 branch :)

https://github.com/TomLingham/Laravel-Searchy/tree/1.0

Installation

Add "tom-lingham/searchy" : "2.*" to your composer.json file under require:

"require": {
  "laravel/framework": "5.*",
  "tom-lingham/searchy" : "2.*"
}

Run composer update in your terminal to pull down the package into your vendors folder.

Add the service provider to the providers array in Laravel's ./config/app.php file:

TomLingham\Searchy\SearchyServiceProvider::class

Add the Alias to the aliases array in Laravel's ./config/app.php file if you want to have quick access to it in your application:

'Searchy' => TomLingham\Searchy\Facades\Searchy::class

Usage

To use Searchy, you can take advantage of magic methods.

If you are searching the name and email column/field of users in a users table you would, for example run:

$users = Searchy::users('name', 'email')->query('John Smith')->get();

You can also write this as:

$users = Searchy::search('users')->fields('name', 'email')->query('John Smith')->get();

In this case, pass the columns you want to search through to the fields() method.

These examples both return an array of Objects containing your search results. You can use getQuery() instead of get() to return an instance of the Database Query Object in case you want to do further manipulation to the results:

$users = Searchy::search('users')->fields('name', 'email')->query('John Smith')
    ->getQuery()->having('relevance', '>', 20)->get();

Limit on results returned

To limit your results, you can use Laravel's built in DatabaseQuery Builder method and chain further methods to narrow your results.

// Only get the top 10 results
$users = Searchy::search('users')->fields('name', 'email')->query('John Smith')
    ->getQuery()->limit(10)->get();

Searching multiple Columns

You can also add multiple arguments to the list of fields/columns to search by.

For example, if you want to search the name, email address and username of a user, you might run:

$users = Searchy::users('name', 'email', 'username')->query('John Smith')->get();

If you need to build your table list dynamically, you can also pass an array of fields instead as the first argument (All other following arguments will be ignored):

$users = Searchy::users(['name', 'email', 'username'])->query('John Smith')->get();

Searching Joined/Concatenated Columns

Sometimes you may want to leverage searches on concatenated column. For example, on a first_name and last_name field but you only want to run the one query. To do this can separate columns with a double colon:

$users = Searchy::users('first_name::last_name')->query('John Smith')->get();

Soft Deleted Records

By default soft deletes will not be included in your results. However, if you wish to include soft deleted records you can do so by adding the withTrashed() after specifying your table and fields;

Searchy::users('name')->withTrashed()->query('Batman')->get();

Return only specific columns

You can specify which columns to return in your search:

$users = Searchy::users('first_name::last_name')->query('John Smith')->select('first_name')->get();

// Or you can swap those around...
$users = Searchy::users('first_name::last_name')->select('first_name')->query('John Smith')->get();

This will, however, also return the relevance aliased column regardless of what is entered here.

How to get a Laravel Eloquent Collection

Transforming the search results into a collection of Laravel Eloquent models is outside the scope of this project. However, an easy way to achieve this without hitting your database more than necessary is to use the Eloquent hydrate() method.

\App\User::hydrate(Searchy::users('name', 'email')->query('Andrew')->get());

This method creates a collection of models from a plain arrays. This is just our case because Searchy results are provided as arrays, and using hydrate we will converted them to instances of User model.

Unicode Characters Support

If you are having issues with the returned results because you have unicode characters in your search data, you can use the FuzzySearchUnicodeDriver.

PLEASE NOTE: There is no sanitization of strings passed through to the FuzzySearchUnicodeDriver prior to inserting into raw MySQL statements. You will have to sanitize the string yourself first or risk opening up your application to SQL injection attacks. You have been warned.

To use, first follow the instructions to publish your configuration file (php artisan vendor:publish) and change your default driver from fuzzy to ufuzzy.

return [

    'default' => 'ufuzzy',

  ...
]

Configuration

You can publish the configuration file to your app directory and override the settings by running php artisan vendor:publish to copy the configuration to your config folder as searchy.php

You can set the default driver to use for searches in the configuration file. Your options (at this stage) are: fuzzy, simple and levenshtein.

You can also override these methods using the following syntax when running a search:

Searchy::driver('fuzzy')->users('name')->query('Batman')->get();

Drivers

Searchy takes advantage of 'Drivers' to handle matching various conditions of the fields you specify.

Drivers are simply a specified group of 'Matchers' which match strings based on specific conditions.

Currently there are only three drivers: Simple, Fuzzy and Levenshtein (Experimental).

Simple Search Driver

The Simple search driver only uses 3 matchers each with the relevant multipliers that best suited my testing environments.

protected $matchers = [
  'TomLingham\Searchy\Matchers\ExactMatcher'                 => 100,
  'TomLingham\Searchy\Matchers\StartOfStringMatcher'         => 50,
  'TomLingham\Searchy\Matchers\InStringMatcher'              => 30,
];

Fuzzy Search Driver

The Fuzzy Search Driver is simply another group of matchers setup as follows. The multipliers are what I have used, but feel free to change these or roll your own driver with the same matchers and change the multipliers to suit.

protected $matchers = [
  'TomLingham\Searchy\Matchers\ExactMatcher'                 => 100,
  'TomLingham\Searchy\Matchers\StartOfStringMatcher'         => 50,
  'TomLingham\Searchy\Matchers\AcronymMatcher'               => 42,
  'TomLingham\Searchy\Matchers\ConsecutiveCharactersMatcher' => 40,
  'TomLingham\Searchy\Matchers\StartOfWordsMatcher'          => 35,
  'TomLingham\Searchy\Matchers\StudlyCaseMatcher'            => 32,
  'TomLingham\Searchy\Matchers\InStringMatcher'              => 30,
  'TomLingham\Searchy\Matchers\TimesInStringMatcher'         => 8,
];

Levenshtein Search Driver (Experimental)

The Levenshtein Search Driver uses the Levenshetein Distance to calculate the 'distance' between strings. It requires that you have a stored procedure in MySQL similar to the following levenshtein( string1, string2 ). There is an SQL file with a suitable function in the res folder - feel free to use this one.

protected $matchers = [
  'TomLingham\Searchy\Matchers\LevenshteinMatcher' => 100
];

Matchers

ExactMatcher

Matches an exact string and applies a high multiplier to bring any exact matches to the top.

StartOfStringMatcher

Matches Strings that begin with the search string. For example, a search for 'hel' would match; 'Hello World' or 'helping hand'

AcronymMatcher

Matches strings for Acronym 'like' matches but does NOT return Studly Case Matches For example, a search for 'fb' would match; 'foo bar' or 'Fred Brown' but not 'FreeBeer'.

ConsecutiveCharactersMatcher

Matches strings that include all the characters in the search relatively positioned within the string. It also calculates the percentage of characters in the string that are matched and applies the multiplier accordingly.

For Example, a search for 'fba' would match; 'Foo Bar' or 'Afraid of bats', but not 'fabulous'

StartOfWordsMatcher

Matches the start of each word against each word in a search.

For example, a search for 'jo ta' would match; 'John Taylor' or 'Joshua B. Takeshi'

StudlyCaseMatcher

Matches Studly Case strings using the first letters of the words only

For example a search for 'hp' would match; 'HtmlServiceProvider' or 'HashParser' but not 'hasProvider'

InStringMatcher

Matches against any occurrences of a string within a string and is case-insensitive.

For example, a search for 'smi' would match; 'John Smith' or 'Smiley Face'

TimesInStringMatcher

Matches a string based on how many times the search string appears inside the string it then applies the multiplier for each occurrence. For example, a search for 'tha' would match; 'I hope that that cat has caught that mouse' (3 x multiplier) or 'Thanks, it was great!' (1 x multiplier)

LevenshteinMatcher

See Levenshtein Driver

Extending

Drivers

It's really easy to roll your own search drivers. Simply create a class that extends TomLingham\Searchy\SearchDrivers\BaseSearchDriver and add a property called $matchers with an array of matcher classes as the key and the multiplier for each matcher as the values. You can pick from the classes that are already included with Searchy or you can create your own.

Matchers

To create your own matchers, you can create your own class that extends TomLingham\Searchy\Matchers\BaseMatcher and (for simple Matchers) override the formatQuery method to return a string formatted with % wildcards in required locations. For more advanced extensions you may need to override the buildQuery method and others as well.

Contributing & Reporting Bugs

If you would like to improve on the code that is here, feel free to submit a pull request.

If you find any bugs, submit them here and I will respond as soon as possible. Please make sure to include as much information as possible.

GitHub

https://github.com/TomLingham/Laravel-Searchy
Comments
  • 1. Static

    I get error when i use

    public function getSearch($value='') { //$users = Searchy::users('first_name', 'email', 'last_name')->query($value)->get(); //$users = Searchy::search('users')->query($value)->get(); $users = Searchy::search('users')->query('John Smith'); // return Response::json($users->toArray()); }

    Non-static method TomLingham\Searchy\SearchBuilder::search() should not be called statically, assuming $this from incompatible context

    Reviewed by marijang at 2014-07-22 09:33
  • 2. Syntax error when searching "key" column

    SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key = 'global', 100, 0) + IF(key LIKE 'global%', 50, 0) + IF(key LIKE 'G% L% O% ' at line 1 (SQL: select *, IF(key = 'global', 100, 0) + IF(key LIKE 'global%', 50, 0) + IF(key LIKE 'G% L% O% B% A% L%', 42, 0) + IF(REPLACE(key, '.', '') LIKE '%g%l%o%b%a%l%', ROUND(40 * (CHAR_LENGTH( 'global' ) / CHAR_LENGTH( REPLACE(key, ' ', '') ))), 0) + IF(key LIKE 'global%', 35, 0) + IF( CHAR_LENGTH( TRIM(key)) = CHAR_LENGTH( REPLACE( TRIM(key), ' ', '')) AND key LIKE BINARY 'G%L%O%B%A%L%', 32, 0) + IF(key LIKE '%global%', 30, 0) + 8 * ROUND (( CHAR_LENGTH(key) - CHAR_LENGTH( REPLACE ( LOWER(key), lower('global'), '')) ) / LENGTH('global')) AS relevance from table having relevance > 0 order by relevance desc limit 100)

    Reviewed by dciancu at 2016-01-08 02:08
  • 3. Pagination of results

    Hey!

    Just installed Searchy and the searching itself works great. However, I'm wondering if it's possible to paginate the results?

    I'm comparing it to using the Query Builder and paginating the results as such:

        $jobMatches = Job::where('title', 'like', $searchQuery)
            ->orWhere('description', 'like', $searchQuery)
            ->paginate($this->numPerPage)
            ->sortByDesc('published_at')
            ->all();
    

    I would love to do the same thing, something like this:

        $jobMatches = Searchy::search('jobs')
            ->fields('title', 'description')
            ->query($searchQuery)
            ->getQuery()
            ->having('relevance', '>', 10)
            ->paginate($this->numPerPage)
            ->get();
    

    Am I missing something obvious to make this work, or is this just something I'll have to dream of? :smile:

    Reviewed by ankhuve at 2016-08-06 00:40
  • 4. many query

    Hi! how i can use many query? for example i wonna find all skills where have word indesign and photoshop :) Searchy::driver('ufuzzy')->skills('name')->query('indesign', 'photoshop')->get();

    Reviewed by Alexmg86 at 2016-07-12 14:48
  • 5. SQLSTATE[42000]: Syntax error or access violation

    Query: Searchy::search('categories')->fields('title')->query($keyword)->getQuery()->limit(3)->get();

    Result

    SQLSTATE[42000]: Syntax error or access violation: 1463 Non-grouping field 'relevance' is used in HAVING clause (SQL: select *, IF(COALESCE(title, '') = 'keyword', 100, 0) + IF(COALESCE(title, '') LIKE 'keyword%', 50, 0) + IF(COALESCE(title, '') LIKE 'K% E% Y% W% O% R% D%', 42, 0) + IF( REPLACE(COALESCE(title, ''), '.', '') LIKE '%k%e%y%w%o%r%d%', ROUND(40 * ( CHAR_LENGTH( 'keyword' ) / CHAR_LENGTH( REPLACE(COALESCE(title, ''), ' ', '') ))), 0) + IF(COALESCE(title, '') LIKE 'keyword%', 35, 0) + IF( CHAR_LENGTH( TRIM( COALESCE(title, '') )) = CHAR_LENGTH( REPLACE( TRIM( COALESCE(title, '') ), ' ', '')) AND COALESCE(title, '') LIKE BINARY 'K%E%Y%W%O%R%D%', 32, 0) + IF(COALESCE(title, '') LIKE '%keyword%', 30, 0) + 8 * ROUND(( CHAR_LENGTH(COALESCE(title, '')) - CHAR_LENGTH( REPLACE( LOWER(COALESCE(title, '')), lower('keyword'), '')) ) / LENGTH('keyword')) AS relevance from categories having relevance > 0 order by relevance desc limit 3)

    Reviewed by J-Brk at 2016-11-22 16:43
  • 6. Could not load package tom-lingham/searchy in http://repo.packagist.org: [UnexpectedValueException] Could not parse version constraint ^7.*: Invalid version string "^7.*"

    I keep receiving this error when trying to run 'composer update' to update other packages and can't pinpoint what is causing it:

      [RuntimeException]                                                                                                                                                          
      Could not load package tom-lingham/searchy in http://repo.packagist.org: [UnexpectedValueException] Could not parse version constraint ^7.*: Invalid version string "^7.*"  
                                                                                                                                                                                  
    
                                                                              
      [UnexpectedValueException]                                              
      Could not parse version constraint ^7.*: Invalid version string "^7.*"  
    

    I read somewhere about zsh using ^7 as a command but i've searched through and cannot find any raw use of ^7 that isn't inside a string - it's something to do with this package or it's dependencies though as removing the search dependency fixes things.

    I've tried requiring specific versions of this package and also specific commits with no luck ( I thought it may be to do with allowing newer versions of Laravel)

    Anyone else getting this?

    I'm using Laravel 5.8

    Reviewed by fri3ndly at 2020-09-28 10:15
  • 7. Question: How can I use relations?

    Dear,

    Searchy is amazing tool. Thanks for sharing.

    I have question about using Larave-Searchy. How can I use relations or Eloquent with method during searcing?

    Reviewed by Kolesar at 2016-06-25 00:44
  • 8. SQLSTATE[42000]: Syntax error or access violation: 1463 Non-grouping field 'relevance' is used in HAVING clause

    This happens in Laravel 5.3, and has happened both for the default search driver and levenshtein.

    It would appear to be down to L 5.3 having "strict" mode set to true in the config/database.php file, under the MYSQL connection setting.

    Unsure about a way round this, as my MYSQL isn't amazingly strong, but I've bypassed it for the moment by making that value false.

    Hope this can help someone else.

    Reviewed by krisscox at 2016-11-02 14:33
  • 9. orderby not working

    How can i use orderby? Its not working in this code

     $all_products = shoe::hydrate(Searchy::search('shoe')
                    ->fields('keywords','type.type')
                    ->query($keywords)
                    ->getQuery()
                    ->join('uploaded_by', function ($join) {
                        $join->on('shoe.user_id', '=', 'uploaded_by.user_id');
                    })
                    ->join('brand', function ($join){
                        $join->on('shoe.brand_id', '=', 'brand.brand_id');
                    })
                    ->join('type', function ($join){
                        $join->on('shoe.type_id', '=', 'type.type_id');
                    })
                    ->where('shoe.visible','=', 1)
                    ->where('shoe.power','=', 1)
                    ->having('relevance', '>', 10)
                    ->orderby('shoe.release_date','desc')
                    ->orderby('shoe.is_ad','desc')
                    ->get());
    
    Reviewed by EyobDejene at 2017-12-29 14:42
  • 10. Add Laravel 5.5 support

    This pull request replace #78 and #79 based on feedback.

    • Added support for Laravel 5.5
    • Added tests for PHP version 7.1 and 7.2
    • Removed tests for HHVM

    This should be good to merge into the 3.0 release since it doesn't break anything. This could alternatively be released in a new minor release.

    Reviewed by vinkla at 2017-08-12 08:59
  • 11. Class name must be a valid object or a string

    My Laravel is 5.3,I use ufuzzy,

    return [
    
        'default' => 'ufuzzy',
    
            ...
    ]
    

    error:

    FatalThrowableError in SearchBuilder.php line 104:
    Class name must be a valid object or a string
    

    And,I use fuzzy, error:

    SQLSTATE[42000]: Syntax error or access violation: 1463 Non-grouping field 'relevance' is used in HAVING clause
    
    Reviewed by zwl1619 at 2016-09-28 21:19
  • 12. Future of Laravel Searchy

    TL;DR I'm no longer maintaining this package but will help support a transition.

    So, it's been a while since I've been able to give any substantial focus to this project. I understand a lot of people still use and rely on this package and I appreciate your enthusiasm for what was supposed to originally be just a hack. While I don't have the time or the desire to update and maintain this I would like to give the project back to the community as responsibly as I can.

    The reasons why I am stopping maintaining Laravel Searchy are numerous, but the main reason is that I don't do any PHP development anymore. Therefore, for me to update and maintain it is a non-trivial exercise. I'm also not close enough with the community to be able to do my due diligence in understanding the direction and needs of it at large. Continuing to publish updates that I don't even test is irresponsible and I won't be doing that any more.

    To facilitate this project transitioning to it's close, I will only accept pull requests that link to popular forks or alternative projects in the README (what is popular will still be up to me - likely it will require some number of GitHub stars, downloads or community participation).

    I will not be publishing any new versions of the package tom-lingham/searchy.

    A big thanks to everyone who used Laravel Searchy and especially those that contributed back to the project over the years.

    Reviewed by TomLingham at 2020-10-11 08:07
Laravel package to search through multiple Eloquent models. Supports sorting, pagination, scoped queries, eager load relationships and searching through single or multiple columns.

Laravel Cross Eloquent Search This Laravel package allows you to search through multiple Eloquent models. It supports sorting, pagination, scoped quer

Jun 27, 2022
Sphinx Search library provides SphinxQL indexing and searching features

Sphinx Search Sphinx Search library provides SphinxQL indexing and searching features. Introduction Installation Configuration (simple) Usage Search I

Mar 14, 2022
Fulltext indexing and searching for Laravel

Laravel fulltext index and search This package creates a MySQL fulltext index for models and enables you to search through those. Install Install with

Jun 5, 2022
Laravel Scout provides a driver based solution to searching your Eloquent models.

Introduction Laravel Scout provides a simple, driver-based solution for adding full-text search to your Eloquent models. Once Scout is installed and c

Jun 29, 2022
Think-scout - A driver based solution to searching your models. Inspired By Laravel Scout

前言 whereof/think-scout根据thinkphp设计思想参考laravel/scout进行扩展 whereof/think-scout 为模型的全文搜索提供了一个简单的、基于驱动程序的解决方案。 目前,Scout 自带了一个 Elasticsearch 驱动;而编写自定义驱动程序很简

Mar 18, 2022
This package offers advanced functionality for searching and filtering data in Elasticsearch.

Scout Elasticsearch Driver ?? Introducing a new Elasticsearch ecosystem for Laravel. ?? This package offers advanced functionality for searching and f

Jul 1, 2022
Plastic is an Elasticsearch ODM and mapper for Laravel. It renders the developer experience more enjoyable while using Elasticsearch, by providing a fluent syntax for mapping, querying, and storing eloquent models.
Plastic is an Elasticsearch ODM and mapper for Laravel. It renders the developer experience more enjoyable while using Elasticsearch, by providing a fluent syntax for mapping, querying, and storing eloquent models.

Plastic is an Elasticsearch ODM and mapper for Laravel. It renders the developer experience more enjoyable while using Elasticsearch, by providing a f

Jun 25, 2022
Search among multiple models with ElasticSearch and Laravel Scout
Search among multiple models with ElasticSearch and Laravel Scout

For PHP8 support use php8 branch For Laravel Framework < 6.0.0 use 3.x branch The package provides the perfect starting point to integrate ElasticSear

Jun 26, 2022
This is an open source demo of smart search feature implemented with Laravel and Selectize plugin
This is an open source demo of smart search feature implemented with Laravel and Selectize plugin

Laravel smart search implementation See demo at: http://demos.maxoffsky.com/shop-search/ Tutorial at: http://maxoffsky.com/code-blog/laravel-shop-tuto

May 28, 2022
A search package for Laravel 5.

Search Package for Laravel 5 This package provides a unified API across a variety of different full text search services. It currently supports driver

Jun 16, 2022
A php trait to search laravel models

Searchable, a search trait for Laravel Searchable is a trait for Laravel 4.2+ and Laravel 5.0 that adds a simple search function to Eloquent Models. S

Jun 23, 2022
Driver for Laravel Scout search package based on https://github.com/teamtnt/tntsearch
Driver for Laravel Scout search package based on https://github.com/teamtnt/tntsearch

TNTSearch Driver for Laravel Scout - Laravel 5.3 - 8.0 This package makes it easy to add full text search support to your models with Laravel 5.3 to 8

Jun 29, 2022
Build and execute an Elasticsearch search query using a fluent PHP API
Build and execute an Elasticsearch search query using a fluent PHP API

PACKAGE IN DEVELOPMENT, DO NOT USE YET Build and execute ElasticSearch queries using a fluent PHP API This package is a lightweight query builder for

Jun 16, 2022
A fully featured full text search engine written in PHP
A fully featured full text search engine written in PHP

TNTSearch TNTSearch is a full-text search (FTS) engine written entirely in PHP. A simple configuration allows you to add an amazing search experience

Jun 28, 2022
SphinxQL Query Builder generates SphinxQL, a SQL dialect, which is used to query the Sphinx search engine. (Composer Package)

Query Builder for SphinxQL About This is a SphinxQL Query Builder used to work with SphinxQL, a SQL dialect used with the Sphinx search engine and it'

Jun 6, 2022
Kirby docs search workflow for Alfred
Kirby docs search workflow for Alfred

Kirby Docs search workflow for Alfred 4 An ultra-fast Kirby Docs search workflow for Alfred 4 Installation Download the latest version Install the wor

Feb 22, 2022
A TYPO3 extension that integrates the Apache Solr search server with TYPO3 CMS. dkd Internet Service GmbH is developing the extension. Community contributions are welcome. See CONTRIBUTING.md for details.
A TYPO3 extension that integrates the Apache Solr search server with TYPO3 CMS. dkd Internet Service GmbH is developing the extension. Community contributions are welcome. See CONTRIBUTING.md for details.

Apache Solr for TYPO3 CMS A TYPO3 extension that integrates the Apache Solr enterprise search server with TYPO3 CMS. The extension has initially been

Jun 14, 2022
A site search engine
A site search engine

THIS PACKAGE IS IN DEVELOPMENT, DO NOT USE IN PRODUCTION YET A site search engine This package can crawl your entire site and index it. Support us We

Jun 15, 2022
Support search in flarum by sonic

flarum-sonic Support search by Sonic Install Sonic following this guide Install the extension: composer require ganuonglachanh/sonic Change info in a

Jun 25, 2022