best-served-cold/laravel-zendsearch

ZendSearch implementation for Laravel - Local file based search engine

1.0.6 2017-02-20 22:20 UTC

README

Build Status Build Status Code Coverage Scrutinizer Code Quality Latest Stable Version SensioLabsInsight

A fast implementation of ZendSearch hooking into Laravel eloquent. Utilise the power of Lucene without installing a secondary service such as Elasticsearch or Solr.

After using a couple of packages for ZendSearch in Laravel I was disappointed with the performance, so I created my own.

Installation

Follow these steps to get the package in place:

Setup

composer require best-served-cold/laravel-zendsearch

Update composer and then add the ServiceProvider to config/app.php:

'providers' => [
  // ...
    BestServedCold\LaravelZendSearch\Laravel\ServiceProvider::class,
],

I'm not keen on Facades, but if you want to use one, add it to the aliases in config/app.php:

'aliases' => [
   // ...
    'Search' => BestServedCold\LaravelZendSearch\Laravel\Facade::class,
],

Publish

Get your config published:

php artisan vendor:publish

Usage

Indexing

Add the SearchTrait and use it in the models you want to use:


// ...

use BestServedCold\LaravelZendSearch\Laravel\SearchTrait;

class User extends Model
{
    use SearchTrait;

// ...

Then add the method searchFields() and populate it with the fields you want to be indexed:

// ...
    public static function searchFields()
    {
        self::setSearchFields(['some', 'fields']);
    }
// ...

If you want to "boost" fields, then add the following method:

// ...
    public static function boostFields()
    {
        self::setBoostFields(['some' => 0.8, 'fields' => 1.0]);
    }
// ...

The index will build automatically from there.

Relations

If you want to index relations, make sure you create your getRelationAttribute() method and then add the relation to the protected $appends = [$relation]; array in your model.

Building

If you have existing data or have changed your search fields, you can rebuild the index from scratch:

php artisan search:rebuild --verbose

Destroy:

php artisan search:destroy --verbose

Optimise:

php artisan search:optmise --verbose

I'll work on a scheduler in the near future, but make sure you optimise your index regularly. I'd suggest scheduling it yourself for now every hour or so.

Searching

Basic

Create a search instance:

$search = UserModel::search();

// add your query
$search->where('string', 'field');

// add an exact match
$search->match('string', 'field');

// Search all fields
$search->where('string');

// limit your query
$search->limit(10);

// get your hits (primary keys in an array)
$ids = $search->hits();

// and or, get your eloquent collection
$result = $search->get();

// Or chain it:
$result = User::search()->where('term', 'field')->limit(15)->offset(10)->get();

Deleting

// Make sure you've got a collection like so
User::search()->where('term', 'field')->first()->delete();

Advanced

$search = UserModel::search();

// Wildcard
$search->wildcard('ter*', 'field');

// Phrase
$search->phrase('this is the phrase', 'field', [1, 2, 3, 4]);

// Fuzzy
$search->fuzzy('term', 'field');

// Term
$search->term('complete_term', 'field');

// Get the last query
BestServedCold\LaravelZendSearch\Lucene\Search::getLastQuery()->__toString();

Filters

There are two basic filters implemented in the configuration which you can override, StopWords and ShortWords. You can, however, change both the filters and the analyzer manually to preset ZendSearch classes or custom classes:

BestServedCold\LaravelZendSearch\Lucene\Filter::setAnalyzer(
    new ZendSearch\Lucene\Analysis\Analyzer\Common\Utf8Num\CaseInsensitive;
);

BestServedCold\LaravelZendSearch\Lucene\Filter::addFilter(
    new ZendSearch\Lucene\Analysis\TokenFilter\LowerCaseUtf8;
);

Helpers

To assist in debugging, there are a few helpers which can assist:

// Returns the last ZendSearch\Lucene\Document inserted.
var_dump(BestServedCold\LaravelZendSearch\Lucene\Store::getLastInsert());

// Returns the current set of filters or analyzer
var_dump(BestServedCold\LaravelZendSearch\Lucene::getFilters());
var_dump(BestServedCold\LaravelZendSearch\Lucene::getAnalyzer());

// Returns the last ZendSearch\Lucene\Search\Query\Boolean object to interrogate.
var_dump(BestServedCold\LaravelZendSearch\Lucene::getLastQuery()->__toString());

Features to come

This is the first stable version which I've made mainly for my own use on another project. I will add the following in due course though.

  • Scheduled optimisation out of the box
  • Option passthrough added for Wildcard, Phrase, Fuzzy
  • Add in highlighting options