Full-Text Search
The Laravel-OpenSearch integration introduces an intuitive and powerful approach to full-text search, extending the familiar Eloquent syntax with OpenSearch'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.
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 OpenSearch'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.
In $model->searchHighlights
only the top level fields are the object keys (as is with normal model attributes).
Ex: $model->searchHighlights->manufacturer['location']['country']
The array in $model->searchHighlightsAsArray
is a flat associative array with the field names (in dot notation) as keys.
Ex: $model->searchHighlights[manufacturer.location.country]
$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.
This is not an instance of the model, so you cannot call any model methods on it (like save, update, etc). This is intentional to avoid accidentally saving the highlighted data to the database.
For multiple fragments, the values are concatenated with .....
@foreach ($products as $product)
<tr>
<td>{!! $product->withHighlights->name !!}</td>
<td>{!! $product->withHighlights->description !!}</td>
</tr>
@endforeach