PHPackages                             nqxcode/laravel-lucene-search - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. nqxcode/laravel-lucene-search

ActiveLibrary[Database &amp; ORM](/categories/database)

nqxcode/laravel-lucene-search
=============================

Laravel 5.5 package for full-text search over Eloquent models based on ZendSearch Lucene.

v2.4.1.1(8y ago)7216.5k26[5 issues](https://github.com/nqxcode/laravel-lucene-search/issues)MITPHPPHP &gt;=5.6.4

Since Oct 15Pushed 5y ago3 watchersCompare

[ Source](https://github.com/nqxcode/laravel-lucene-search)[ Packagist](https://packagist.org/packages/nqxcode/laravel-lucene-search)[ RSS](/packages/nqxcode-laravel-lucene-search/feed)WikiDiscussions master Synced today

READMEChangelog (10)Dependencies (7)Versions (73)Used By (0)

Laravel 5.5 Lucene search
=========================

[](#laravel-55-lucene-search)

[![Latest Stable Version](https://camo.githubusercontent.com/06dd72dae2cafa7b247a738c9ab722dca53effb984e0d0feb280efb28ed20ca9/68747470733a2f2f706f7365722e707567782e6f72672f6e7178636f64652f6c61726176656c2d6c7563656e652d7365617263682f762f737461626c652e706e67)](https://packagist.org/packages/nqxcode/laravel-lucene-search)[![Latest Unstable Version](https://camo.githubusercontent.com/a288a148663af9420746e581532c07ad441e6b17caeae7cf4ff68bf6dee46960/68747470733a2f2f706f7365722e707567782e6f72672f6e7178636f64652f6c61726176656c2d6c7563656e652d7365617263682f762f756e737461626c652e706e67)](https://packagist.org/packages/nqxcode/laravel-lucene-search)[![License](https://camo.githubusercontent.com/3980f48d30e5a17bf0d56b77543869931dc199ce609d648840ab935df7d5e67a/68747470733a2f2f706f7365722e707567782e6f72672f6e7178636f64652f6c61726176656c2d6c7563656e652d7365617263682f6c6963656e73652e706e67)](https://packagist.org/packages/nqxcode/laravel-lucene-search)[![Build Status](https://camo.githubusercontent.com/9338438b1a1557f53977ef16759d54b95077e14c06814cb7b71d8787e7eeccdc/68747470733a2f2f7472617669732d63692e6f72672f6e7178636f64652f6c61726176656c2d6c7563656e652d7365617263682e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/nqxcode/laravel-lucene-search)[![Coverage Status](https://camo.githubusercontent.com/922f1d53917928c69131fba70296bdd8c4b1396a2ebe2aaa4ea0d107e4a8a555/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f6e7178636f64652f6c61726176656c2d6c7563656e652d7365617263682f6d61737465722e7376673f7374796c653d666c6174)](https://coveralls.io/r/nqxcode/laravel-lucene-search?branch=master)

Laravel 5.5 package for full-text search over Eloquent models based on ZendSearch Lucene.

Installation
------------

[](#installation)

Require this package in your composer.json and run composer update:

```
{
	"require": {
        "nqxcode/laravel-lucene-search": "2.4.*"
	}
}
```

After updating composer, add the ServiceProvider to the providers array in `config/app.php`

```
'providers' => [
	Nqxcode\LuceneSearch\ServiceProvider::class,
],
```

If you want to use the facade to search, add this to your facades in `config/app.php`:

```
'aliases' => [
	'Search' => Nqxcode\LuceneSearch\Facade::class,
],
```

Configuration
-------------

[](#configuration)

Publish the config file into your project by running:

```
php artisan vendor:publish --provider="Nqxcode\LuceneSearch\ServiceProvider"
```

### Basic

[](#basic)

In published config file add descriptions for models which need to be indexed, for example:

```
'index' => [

	// ...

	namespace\FirstModel::class => [
		'fields' => [
			'name', 'full_description', // fields for indexing
		]
	],

	namespace\SecondModel::class => [
		'fields' => [
			'name', 'short_description', // fields for indexing
		]
	],

	namespace\ModelWithCustomPrimaryKey::class => [
		// You can also define your primary key (if you use something else than "id")
		'primary_key' => 'my_custom_field_name',
		'fields' => [
			'username', 'short_description', // fields for indexing
		]
	],

	// ...

],
```

### Indexing of dynamic fields

[](#indexing-of-dynamic-fields)

You can also index values of **optional fields** (dynamic fields). For enable indexing for optional fields:

- In config for each necessary model add following option:

```
        'optional_attributes' => true

        // or

        'optional_attributes' => [
                'accessor' => 'custom_name' // with specifying of accessor name
        ]
```

- In model add **special accessor**, that returns list of `field-name => field-value`. By default `getOptionalAttributesAttribute` accessor will be used. In case accessor name specified in config `getCustomNameAttribute` accessor will be used.

Example:

In config file:

```
        namespace\FirstModel::class => [
                'fields' => [
                    'name', 'full_description', // fixed fields for indexing
                ],

                'optional_attributes' => true //  enable indexing for dynamic fields
        ],
```

In model add following accessor:

```
        public function getOptionalAttributesAttribute()
        {
                return [
                        'optional_attribute1' => 'value1',
                        'optional_attribute2' => 'value2',
                ];
        }
```

### Score Boosting

[](#score-boosting)

See details on [Apache Lucene - Scoring](https://lucene.apache.org/core/3_5_0/scoring.html#Score%20Boosting).

#### Model level boosting

[](#model-level-boosting)

This is **Document level boosting** in terminology of Apache Lucene. By default all models have **boost** value equal to **1**. For change of this behavior customize boost for necessary models as in the following examples.

- In config for each necessary model add following option:

```
        'boost' => true

        // or

        'boost' => [
                'accessor' => 'custom_name' // with specifying of accessor name
        ]
```

In model add following accessor:

```
        public function getBoostAttribute()
        {
                return 0.5; // customize boost value for model
        }
```

- In model add **special accessor**, that returns boost value. By default `getBoostAttribute` accessor will be used. In case accessor name specified in config `getCustomNameAttribute` accessor will be used.

Example:

In config file:

```
        namespace\FirstModel::class => [
                'fields' => [
                    'name', 'full_description',
                ],

                'boost' => true // enable boosting for model
        ],
```

In model add following accessor:

```
        public function getBoostAttribute()
        {
                return 0.5; // customize boost value for model
        }
```

#### Model's field level boosting

[](#models-field-level-boosting)

This is **Document's Field level boosting** in terminology of Apache Lucene. By default **boost** is set in **1** for each field. For change of this behavior set boost for necessary fields as in the following examples.

In config file:

```
        namespace\FirstModel::class => [
                'fields' => [
                    'name', // field with default boost
                    'full_description' => ['boost' => 0.2], // customize boost value
                ],
        ],
```

Or/and in model accessor:

```
        public function getOptionalAttributesAttribute()
        {
                return [
                        'optional_attribute1' => 'value1', // field with default boost
                        'optional_attribute2' => ['boost' => 0.5, 'value' => 'value2'], // customize boost value
                ];
        }
```

### Stemming and stopwords

[](#stemming-and-stopwords)

By default the following filters are used in search:

- Stemming filter for **english/russian** words (for reducing words to their root form),
- Stopword filters for **english/russian** words (for exclude some words from search index).

This filters can be deleted or replaced with others.

```
'analyzer' => [
    'filters' => [
    	// Default stemming filter.
    	Nqxcode\Stemming\TokenFilterEnRu::class,
    ],

    // List of paths to files with stopwords.
    'stopwords' => Nqxcode\LuceneSearch\Analyzer\Stopwords\Files::get(),
],
```

Usage
-----

[](#usage)

### Artisan commands

[](#artisan-commands)

#### Initialize or rebuild search index

[](#initialize-or-rebuild-search-index)

For building of search index run:

```
php artisan search:rebuild --verbose
```

#### Clear search index

[](#clear-search-index)

For clearing of search index run:

```
php artisan search:clear
```

#### Filtering of models in search results

[](#filtering-of-models-in-search-results)

For filtering of models in search results each model's class can implements `SearchableInterface`. For example:

```
use Illuminate\Database\Eloquent\Model;
use Nqxcode\LuceneSearch\Model\SearchableInterface;

class Dummy extends Model implements SearchableInterface
{
        // ...

        /**
         * Get id list for all searchable models.
         */
        public static function searchableIds()
        {
            return self::wherePublish(true)->pluck('id');
        }

        // ...
}
```

### Partial updating of search index

[](#partial-updating-of-search-index)

For register of necessary events (save/update/delete) `use Nqxcode\LuceneSearch\Model\SearchTrait` in target model:

```
    use Illuminate\Database\Eloquent\Model;
    use Nqxcode\LuceneSearch\Model\SearchableInterface;
    use Nqxcode\LuceneSearch\Model\SearchTrait;

    class Dummy extends Model implements SearchableInterface
    {
        use SearchTrait;

        // ...
    }
```

### Perform operations without indexing

[](#perform-operations-without-indexing)

If you want to avoid triggering the indexing, wrap necessary operations in the `withoutSyncingToSearch()` method on your model:

```
Product::withoutSyncingToSearch(function () {
    // mass update position for product, e.g.
    foreach (Product::all() as $i => $product) {
        $product->update(['position' => $i)]);
    }
});
```

### Query building

[](#query-building)

Build query in several ways:

#### Using constructor:

[](#using-constructor)

By default, queries which will execute search in the **phrase entirely** are created.

##### Simple queries

[](#simple-queries)

```
$query = Search::query('clock'); // search by all fields.
// or
$query = Search::where('name', 'clock'); // search by 'name' field.
// or
$query = Search::query('clock')              // search by all fields with
	->where('short_description', 'analog'); // filter by 'short_description' field.
// or
$query = Product::search('clock'); // search only in `Product` model by all fields in case when `Product` use `SearchableTrait`.
```

##### Advanced queries

[](#advanced-queries)

For `query` and `where` methods it is possible to set the following options:

- **phrase** - phrase match (boolean, true by default)
- **proximity** - value of distance between words (unsigned integer)
- **fuzzy** - value of fuzzy (float, 0 ... 1)
- **required** - should match (boolean, true by default)
- **prohibited** - should not match (boolean, false by default)

###### Examples:

[](#examples)

Find all models in which any field contains phrase like 'composite one two phrase':

```
$query = Search::query('composite phrase', '*', ['proximity' => 2]);
```

Search by each word in query:

```
$query = Search::query('composite phrase', '*', ['phrase' => false]);
```

#### Using Lucene raw queries:

[](#using-lucene-raw-queries)

```
$query = Search::rawQuery('short_description:"analog"');
// or
$rawQuery = QueryParser::parse('short_description:"analog"');
$query = Search::rawQuery($rawQuery);
```

### Getting of results

[](#getting-of-results)

For built query are available following actions:

#### Get all found models

[](#get-all-found-models)

```
$models = $query->get();
```

#### Get count of results

[](#get-count-of-results)

```
$count = $query->count();
```

#### Get limit results with offset

[](#get-limit-results-with-offset)

```
$models = $query->limit(5, 10)->get(); // Limit = 5 and offset = 10
```

#### Paginate the found models

[](#paginate-the-found-models)

```
$paginator = $query->paginate(50);
```

### Highlighting of matches

[](#highlighting-of-matches)

Highlighting of matches is available for any html fragment encoded in **utf-8** and is executed only for the last executed request.

```
Search::find('nearly all words must be highlighted')->get();
$highlighted = Search::highlight('all words');

// highlighted html:
// 'all words'
```

License
-------

[](#license)

Package licenced under the MIT license.

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity38

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity73

Established project with proven stability

 Bus Factor1

Top contributor holds 98.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~28 days

Recently: every ~2 days

Total

71

Last Release

2184d ago

Major Versions

v1.2.3 → v2.2.0.02016-01-24

v1.2.4 → v2.3.0.02017-01-10

v1.3.1 → v2.3.0.22017-04-09

v1.4.0 → v2.0.3.02017-06-15

v1.4.1 → v2.0.3.12017-09-06

PHP version history (3 changes)v1.0.0-beta.1PHP &gt;=5.4.0

v2.1.0PHP &gt;=5.5.9

v2.3.0.0PHP &gt;=5.6.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/75d008474c86762490f249a6f2f1bc5f4728ca2dea466ca26fbb72dfb928a533?d=identicon)[nqxcode](/maintainers/nqxcode)

---

Top Contributors

[![nqxcode](https://avatars.githubusercontent.com/u/5667387?v=4)](https://github.com/nqxcode "nqxcode (217 commits)")[![aurlin](https://avatars.githubusercontent.com/u/45446871?v=4)](https://github.com/aurlin "aurlin (1 commits)")[![bryant1410](https://avatars.githubusercontent.com/u/3905501?v=4)](https://github.com/bryant1410 "bryant1410 (1 commits)")[![HommeSauvage](https://avatars.githubusercontent.com/u/14103714?v=4)](https://github.com/HommeSauvage "HommeSauvage (1 commits)")[![jimpeters](https://avatars.githubusercontent.com/u/1263441?v=4)](https://github.com/jimpeters "jimpeters (1 commits)")

---

Tags

eloquenteloquent-modelsfulltextlaravellucenesearchzendsearchsearchlaraveleloquentfulltextlucenezendsearch

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/nqxcode-laravel-lucene-search/health.svg)

```
[![Health](https://phpackages.com/badges/nqxcode-laravel-lucene-search/health.svg)](https://phpackages.com/packages/nqxcode-laravel-lucene-search)
```

###  Alternatives

[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.7M23](/packages/tucker-eric-eloquentfilter)[mohammad-fouladgar/eloquent-builder

527183.5k](/packages/mohammad-fouladgar-eloquent-builder)[jedrzej/searchable

Searchable trait for Laravel's Eloquent models - filter your models using request parameters

127256.0k4](/packages/jedrzej-searchable)[baril/sqlout

MySQL fulltext driver for Laravel Scout.

4512.3k](/packages/baril-sqlout)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
