Skip to content

Full-Text Search

The Laravel-Elasticsearch integration introduces an intuitive and powerful approach to full-text search, extending the familiar Eloquent syntax with Elasticsearch’s rich querying capabilities. This section outlines how to construct and execute search queries that span across all or selected fields within an index, leveraging various search techniques such as term queries, boosting, fuzzy searches, and regex.

These query methods can be used for full-text search across multiple fields in your model. They work alongside the stsndard where()->get() method, allowing you to search across all and execute the standard Eloquent queries. IE: get(), first(), aggregate(), paginate()

$results = MyModel::searchTerm('XYZ')->get();

searchTerm()

  • searchTerm($term, $fields = ['*'], $options = [])
  • orSearchTerm($term, $fields = ['*'], $options = [])
  • Type: best_fields
$results = Book::searchTerm('Eric')->orSearchTerm('Lean')->searchTerm('Startup')->get();

searchTermMost()

  • searchTermMost($term, $fields = ['*'], $options = [])
  • orSearchTermMost($term, $fields = ['*'], $options = [])
  • Type: most_fields
$results = Book::searchTermMost('quick brown fox', [ "title", "title.original", "title.shingles" ])->get();

searchTermCross()

  • searchTermCross($term, $fields = ['*'], $options = [])
  • orSearchTermCross($term, $fields = ['*'], $options = [])
  • Type: cross_fields
$results = Person::searchTermCross('Will Smith', [ 'first_name','last_name'],['operator' => 'and'])->get();

searchPhrase()

  • searchPhrase($phrase, $fields = ['*'], $options = [])
  • orSearchPhrase($phrase, $fields = ['*'], $options = [])
  • Type: phrase
Product::searchPhrase('United States')->orSearchPhrase('United Kingdom')->sum('orders');

searchPhrasePrefix()

  • searchPhrasePrefix($phrase, $fields = ['*'], $options = [])
  • orSearchPhrasePrefix($phrase, $fields = ['*'], $options = [])
  • Type: phrase_prefix
$results = Person::searchPhrasePrefix('loves espressos and te')->get();

searchBoolPrefix()

  • searchBoolPrefix($phrase, $fields = ['*'], $options = [])
  • orSearchBoolPrefix($phrase, $fields = ['*'], $options = [])
  • Type: bool_prefix
  • Scoring behaves like most_fields, but using a match_bool_prefix query instead of a match query.
$results = Person::searchBoolPrefix('loves espressos and te')->get();

Parameter: $fields

By default, all fields will be searched through; you can specify which to search through as well as optionally boost certain fields using a caret ^:

People:searchTerm('John',['name^3','description^2','friends.name'])->get();

Parameter: $options

Allows you to set any options for the multi_match clause to use, ex:

  • analyzer
  • boost
  • operator
  • minimum_should_match
  • fuzziness
  • lenient
  • prefix_length
  • max_expansions
  • fuzzy_rewrite
  • zero_terms_query

withHighlights()

Highlighting allows you to display search results with the matched terms highlighted:

withHighlights($fields = [], $preTag = '<em>', $postTag = '</em>', $globalOptions = [])

The highlighted results are stored in the model’s metadata and can be accessed via a built-in model attribute using:

  • $model->searchHighlights: returns on object with the found highlights for each field.
  • $model->searchHighlightsAsArray: returns an associative array with the found highlights for each field.

The values of the highlights are always in an array, even if there is only one fragment.

$highlights = [];
$products = Product::searchTerm('espresso')->withHighlights()->get();
foreach ($products as $product) {
$highlights[$product->_id] = $product->searchHighlights;
}

You can filter the fields to highlight:

$highlights = [];
$products = Product::searchTerm('espresso')->withHighlights(['description'],'<strong>','</strong>')->get();
foreach ($products as $product) {
$highlights[$product->_id] = $product->searchHighlights->description ?? [];
}
$highlightFields = [
'name' => [
'pre_tags' => ['<span class="text-primary-500">'],
'post_tags' => ['</span>'],
],
'description' => [
'pre_tags' => ['<span class="text-secondary-500">'],
'post_tags' => ['</span>'],
],
'manufacturer.name' => [
'pre_tags' => ['<span class="text-sky-500">'],
'post_tags' => ['</span>'],
],
];
$highlights = [];
$products = Product::searchTerm('espresso')->withHighlights($highlightFields)->get();
foreach ($products as $product) {
$highlights[$product->_id]['name'] = $product->searchHighlights->name ?? [];
$highlights[$product->_id]['description'] = $product->searchHighlights->description ?? [];
$highlights[$product->_id]['manufacturer'] = $product->searchHighlights->manufacturer['name'] ?? [];
}

Global options can be set for all fields:

$options = [
'number_of_fragments' => 3,
'fragment_size' => 150,
];
$highlights = [];
$products = Product::searchTerm('espresso')->withHighlights([],'<em>','</em>',$options)->get();
foreach ($products as $product) {
$highlights[$product->_id] = $product->searchHighlights;
}

$model->withHighlights->field

This built in attribute will get all the model’s data, parse any user defined mutators, then overwrite any fields that have highlighted data. This is useful when you want to display the highlighted data in a view.

@foreach ($products as $product)
<tr>
<td>{!! $product->withHighlights->name !!}</td>
<td>{!! $product->withHighlights->description !!}</td>
</tr>
@endforeach

searchFor()

  • searchFor($termOrPhrase, $fields = ['*'], $options = [])
  • Convenience method that will either use searchTerm or searchPhrase depending on the word count of $value

Helper: asFuzzy()

  • Will mark the previous clause as fuzzy
Product::searchTerm('remarkble')->asFuzzy()->searchTerm('excellnt')->withHighlights()->get();

Helper: setMinShouldMatch()

  • will set the option {"minimum_should_match": $value} to the previous clause only

Helper: setBoost()

  • will set the option {"boost": $value} to the previous clause only

Opt 2: The Search Query

Unlike the traditional where()->get() method which operates on specific fields, the search method is designed to perform a full-text search across multiple fields, offering a broader search scope.

$results = MyModel::term('XYZ')->search();

Term Search: term()

To search for a single term across all fields in an index:

$results = Book::term('Eric')->search();

Multiple Terms

Combining terms with logical operators (AND/OR):

$results = Book::term('Eric')->orTerm('Lean')->andTerm('Startup')->search();

Phrase Search: phrase()

A phrase is a sequence of words that must appear in the same order as the search query. This is useful for finding exact matches or specific sequences of words.

To search for a phrase across all fields in an index:

$results = Book::phrase('Lean Startup')->search();

Multiple Phrases

Combining phrases with logical operators (AND/OR):

orPhrase($phrase): Searches for documents containing either the original phrase or the specified phrase.

$results = Book::phrase('United States')->orPhrase('United Kingdom')->search();

andPhrase($phrase): Searches for documents containing both the original phrase and the specified phrase.

$results = Book::phrase('Lean Startup')->andPhrase('Eric Ries')->search();

Boosting Terms

Boosting enhances the relevance score of certain terms:

$results = Book::term('Eric', 2)->orTerm('Lean Startup')->search();

Searching Selected Fields

Limiting the search to specific fields:

$results = Book::term('Eric')->fields(['title', 'author', 'description'])->search();

Minimum Should Match

Configures the minimum amount of terms that are required to match

$results = Book::term('Eric')->orTerm('Lean')->orTerm('Startup')->field('title')->field('author')->minShouldMatch(2)->search();

Minimum Score

Sets a minimum relevance score for results:

$results = Book::term('Eric')->field('title', 3)->field('author', 2)->field('description')->minScore(2.1)->search();

Combining Search with Eloquent Queries

Search queries can be blended with standard Eloquent queries:

$results = Book::term('David')->field('title', 3)->field('author', 2)->field('description')->minScore(2.1)->where('is_active', true)->search();

Fuzzy Searches

Fuzzy searches allow for matching terms that are similar to the search term:

$results = Book::fuzzyTerm('quikc')->orFuzzyTerm('brwn')->andFuzzyTerm('foks')->search();

Regular Expressions

Leverage Elasticsearch’s support for regex in your searches:

// Uses regex patterns to match documents
$results = Book::regEx('joh?n(ath[oa]n)')->andRegEx('doey*')->search();

Highlighting

Highlighting allows you to display search results with the matched terms highlighted:

highlight($fields = [], $preTag = '<em>', $postTag = '</em>', $globalOptions = [])

The highlighted results are stored in the model’s metadata and can be accessed via a built-in model attribute using:

  • $model->searchHighlights: returns on object with the found highlights for each field.
  • $model->searchHighlightsAsArray: returns an associative array with the found highlights for each field.

The values of the highlights are always in an array, even if there is only one fragment.

$highlights = [];
$products = Product::term('espresso')->highlight()->search();
foreach ($products as $product) {
$highlights[$product->_id] = $product->searchHighlights;
}

You can filter the fields to highlight:

$highlights = [];
$products = Product::term('espresso')->highlight(['description'],'<strong>','</strong>')->search();
foreach ($products as $product) {
$highlights[$product->_id] = $product->searchHighlights->description ?? [];
}
$highlightFields = [
'name' => [
'pre_tags' => ['<span class="text-primary-500">'],
'post_tags' => ['</span>'],
],
'description' => [
'pre_tags' => ['<span class="text-secondary-500">'],
'post_tags' => ['</span>'],
],
'manufacturer.name' => [
'pre_tags' => ['<span class="text-sky-500">'],
'post_tags' => ['</span>'],
],
];
$highlights = [];
$products = Product::term('espresso')->highlight($highlightFields)->search();
foreach ($products as $product) {
$highlights[$product->_id]['name'] = $product->searchHighlights->name ?? [];
$highlights[$product->_id]['description'] = $product->searchHighlights->description ?? [];
$highlights[$product->_id]['manufacturer'] = $product->searchHighlights->manufacturer['name'] ?? [];
}

Global options can be set for all fields:

$options = [
'number_of_fragments' => 3,
'fragment_size' => 150,
];
$highlights = [];
$products = Product::term('espresso')->highlight([],'<em>','</em>',$options)->search();
foreach ($products as $product) {
$highlights[$product->_id] = $product->searchHighlights;
}

$model->withHighlights->field

This built in attribute will get all the model’s data, parse any user defined mutators, then overwrite any fields that have highlighted data. This is useful when you want to display the highlighted data in a view.

@foreach ($products as $product)
<tr>
<td>{!! $product->withHighlights->name !!}</td>
<td>{!! $product->withHighlights->description !!}</td>
</tr>
@endforeach