Search bundle
Introduction
The main purpose of the search bundle is to index data and search through them. You can index any entity, while the structure of the data will be saved very different. The advantage is a better search results, because the search engine can analyze data and could perform fuzzy search if needed. You can also weight your data, to tell what strings may be more important than other to find the specific resource.
Installation
$ composer require enhavo/search-bundle
To initialize the engine you have to fire the enhavo:search:init
command.
$ bin/console enhavo:search:init
Use the --force
option, if you make changes that affect the index settings. Force will drop the index first and initialize, so you will have an empty index.
$ bin/console enhavo:search:init --force
Search engines
Enhavo comes with some build in search engines. The database
, elasticsearch
and null
engine. Both implements the Enhavo\Bundle\SearchBundle\Engine\SearchEngineInterface
.
Database search engine
With the database search engine the content gets indexed into the database. So no extra service is needed. Therefor all words get separated from each other, simplified and then stored in a database table. In addition to that every word gets a score which determines the relevance to the other stored words.
The downside is, that if your amount of data getting bigger, this engine could get very slow.
By default, the search term has some addons. You have the possibility to get better search results by using the operators AND
and OR
. If you want to exclude a word you can put -
in front of the word and if you want to get results with a whole phrase of words just but them into "
.
Configure the database engine with:
# .env.local
SEARCH_DSN=database://null
Elastic search engine
With the elastic search engine you can index your data in an elasticsearch service and use their power and performance.
# .env.local
SEARCH_DSN=elastic://localhost:9200/elastic_search
Null engine
The null engine is for dev
mode, if you want to turn off the indexing. It will always return an empty result.
# .env.local
SEARCH_DSN=null://null
Indexing
To index an entity we have to add some metadata in order to tell what we would like to index. By default, nothing will be indexed. In this example we define metadata for the entity App\Entity\Book
.
enhavo_search:
metadata:
App\Entity\Book:
index:
title:
type: text
weight: 30
property: title
description:
type: text
weight: 5
property: title
chapters:
type: collection
property: chapters
The properties title
and description
are just a string, so we use the type text
. The key is not enough to tell the name of the property, you have to configure it explicit with property
. You can add als the weight
options, to tell that title
is more important then description
.
Book has also oneToMany
collection of chapters. So we use the type collection
. Other types may be model
for e.g. manyToOne
relations.
You can find more types in the reference section or write your own type.
Note
You can only index root resources. They have to be defined as well.
Define root resources:
enhavo_search:
index:
classes:
- App\Entity\Book
- Enhavo\Bundle\PageBundle\Entity\Page
- Enhavo\Bundle\ArticleBundle\Entity\Article
To index an entity, you can just inject the engine to any service and index the resource.
namespace App\Service;
use Enhavo\Bundle\PageBundle\Repository\PageRepository;
use Enhavo\Bundle\SearchBundle\Engine\SearchEngineInterface;
class MyService
{
public function __construct(
private SearchEngineInterface $searchEngine,
private PageRepository $repository,
) {}
public function index()
{
$page = $this->repository->find(1);
$this->searchEngine->index($page);
}
}
If you want to index all root resources at once just execute the enhavo:search:index
command.
$ bin/console enhavo:search:index
On every enhavo_app.post_create
, enhavo_app.post_update
and enhavo_app.pre_delete
the index will be automatically updated if it is a root resource.
Filter data
If you want to add additional filter data, that you will use during a search, you have to also provide metadata for it.
enhavo_search:
metadata:
App\Entity\Book:
filter:
category:
type: text
property: category.name
Like in index, you have to use the property
config explizit, the key will not be enough. Here we just use a text filter with property chain, because category itself is also an entity.
You can find more types in the reference section or write your own type.
Search
To execute a search programmatically, you have to inject the search engine, create a filter and search. With the ResultConverter
you can change the results and highlight the search term in the text.
namespace App\Service;
use Enhavo\Bundle\SearchBundle\Engine\SearchEngineInterface;
use Enhavo\Bundle\SearchBundle\Result\ResultConverter;
use Enhavo\Bundle\SearchBundle\Engine\Filter\Filter;
class MyService
{
public function __construct(
private SearchEngineInterface $searchEngine,
private ResultConverter $resultConverter,
) {}
public function search()
{
$filter = new Filter();
$filter->setTerm('Hello');
$filter->setFuzzy(true);
$filter->setLimit(10);
$summary = $searchEngine->search($filter);
foreach ($summary->getEntries() as $entry) {
$entity = $entry->getSubject();
}
$results = $resultConverter->convert($summary, $term);
foreach ($results as $entry) {
$title = $entry->getTitle();
$text = $entry->getText(); # highlighted text
$entity = $entry->getSubject();
}
}
}
Auto suggest
With auto suggest, you can auto complete single words. In the background you have to perform a search and the engine will analyze the results for words that start with the search term. So a fuzzy search will be ignored here, because we search occurrences with an exact match.
class MyService
{
public function suggest()
{
$filter = new Filter();
$filter->setTerm('Hel');
$filter->setLimit(10);
$words = $searchEngine->suggest($filter);
foreach ($words as $word) {
}
}
}
Debugging
To check which data will be indexed you can use the debug:search:analyze
command. It will need the FQCN and the id of the resource as arguments
$ bin/console debug:search:analyze "Enhavo\Bundle\PageBundle\Entity\Page" 1
To check what are the results, you can use the enhavo:search
command.
$ bin/console enhavo:search hello
To check the auto suggest results, you use the enhavo:search:suggest
$ bin/console enhavo:search:suggest hel