Index-model field mapping
Define your index-model’s field mapping and embedded relationships to fine-tune your indexed data
Defining a field Map
Section titled “Defining a field Map”By default, the Index Model will be built with all the fields it finds from the Base Model during synchronisation.
However, you can customize this by defining a fieldMap()
method in your Index Model.
use PDPhilip\ElasticLens\Builder\IndexBuilder; use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel{ protected $baseModel = User::class;
public function fieldMap(): IndexBuilder { return IndexBuilder::map(User::class, function (IndexField $field) { $field->text('first_name'); $field->text('last_name'); $field->text('email'); $field->bool('is_active'); //See attributes as fields $field->type('state', UserState::class); //Maps enum $field->text('created_at'); $field->text('updated_at'); }); }
Attributes as fields
Section titled “Attributes as fields”If your Base Model has attributes (calculated values) that you would like to have searchable, you can define them in the fieldMap()
as if they were a regular field.
For example,
$field->bool('is_active')
could be derived from a custom attribute in the Base Model:
// @property-read bool is_active public function getIsActiveAttribute(): bool { return $this->updated_at >= Carbon::now()->modify('-30 days'); }
Be mindful that these values are stored in Elasticsearch at their current state during synchronisation.
Relationships as embedded fields
Section titled “Relationships as embedded fields”The stand-out feature of ElasticLens is the ability to embed relationships within your Index Model. This allows you to create a more structured and searchable index beyond the flat structure of your Base Model.
As an illustration, consider the following relationships around the User
model which will be the base model for our IndexedUser
model.
EmbedsMany
Section titled “EmbedsMany”EX: User
has many Profiles
use PDPhilip\ElasticLens\Builder\IndexBuilder;use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel{ protected $baseModel = User::class;
public function fieldMap(): IndexBuilder { return IndexBuilder::map(User::class, function (IndexField $field) { $field->text('first_name'); $field->text('last_name'); $field->text('email'); $field->bool('is_active'); $field->type('type', UserType::class); $field->type('state', UserState::class); $field->text('created_at'); $field->text('updated_at'); $field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) { $field->text('profile_name'); $field->text('about'); $field->array('profile_tags'); }); }); }
EmbedsOne
Section titled “EmbedsOne”EX: Profile
has one ProfileStatus
use PDPhilip\ElasticLens\Builder\IndexBuilder;use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel{ protected $baseModel = User::class;
public function fieldMap(): IndexBuilder { return IndexBuilder::map(User::class, function (IndexField $field) { $field->text('first_name'); $field->text('last_name'); $field->text('email'); $field->bool('is_active'); $field->type('type', UserType::class); $field->type('state', UserState::class); $field->text('created_at'); $field->text('updated_at'); $field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) { $field->text('profile_name'); $field->text('about'); $field->array('profile_tags'); $field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) { $field->text('id'); $field->text('status'); }); }); }); }
EmbedsBelongTo
Section titled “EmbedsBelongTo”EX: User
belongs to an Account
use PDPhilip\ElasticLens\Builder\IndexBuilder;use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel{ protected $baseModel = User::class;
public function fieldMap(): IndexBuilder { return IndexBuilder::map(User::class, function (IndexField $field) { $field->text('first_name'); $field->text('last_name'); $field->text('email'); $field->bool('is_active'); $field->type('type', UserType::class); $field->type('state', UserState::class); $field->text('created_at'); $field->text('updated_at'); $field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) { $field->text('profile_name'); $field->text('about'); $field->array('profile_tags'); $field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) { $field->text('id'); $field->text('status'); }); }); $field->embedsBelongTo('account', Account::class)->embedMap(function (IndexField $field) { $field->text('name'); $field->text('url'); }); }); }
Embedding without observing/watching
Section titled “Embedding without observing/watching”EX: User
belongs to a Country
and you don’t need to observe the Country
model to trigger a rebuild of the User
model.
use PDPhilip\ElasticLens\Builder\IndexBuilder;use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel{ protected $baseModel = User::class;
public function fieldMap(): IndexBuilder { return IndexBuilder::map(User::class, function (IndexField $field) { $field->text('first_name'); $field->text('last_name'); $field->text('email'); $field->bool('is_active'); $field->type('type', UserType::class); $field->type('state', UserState::class); $field->text('created_at'); $field->text('updated_at'); $field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) { $field->text('profile_name'); $field->text('about'); $field->array('profile_tags'); $field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) { $field->text('id'); $field->text('status'); }); }); $field->embedsBelongTo('account', Account::class)->embedMap(function (IndexField $field) { $field->text('name'); $field->text('url'); }); $field->embedsBelongTo('country', Country::class)->embedMap(function (IndexField $field) { $field->text('country_code'); $field->text('name'); $field->text('currency'); })->dontObserve(); // Don't observe changes in the country model }); }
EmbedsMany with a query
Section titled “EmbedsMany with a query”EX: User
has Many UserLogs
and you only want to embed the last 10:
use PDPhilip\ElasticLens\Builder\IndexBuilder;use PDPhilip\ElasticLens\Builder\IndexField;
class IndexedUser extends IndexModel{ protected $baseModel = User::class;
public function fieldMap(): IndexBuilder { return IndexBuilder::map(User::class, function (IndexField $field) { $field->text('first_name'); $field->text('last_name'); $field->text('email'); $field->bool('is_active'); $field->type('type', UserType::class); $field->type('state', UserState::class); $field->text('created_at'); $field->text('updated_at'); $field->embedsMany('profiles', Profile::class)->embedMap(function (IndexField $field) { $field->text('profile_name'); $field->text('about'); $field->array('profile_tags'); $field->embedsOne('status', ProfileStatus::class)->embedMap(function (IndexField $field) { $field->text('id'); $field->text('status'); }); }); $field->embedsBelongTo('account', Account::class)->embedMap(function (IndexField $field) { $field->text('name'); $field->text('url'); }); $field->embedsBelongTo('country', Country::class)->embedMap(function (IndexField $field) { $field->text('country_code'); $field->text('name'); $field->text('currency'); })->dontObserve(); // Don't observe changes in the country model $field->embedsMany('logs', UserLog::class, null, null, function ($query) { $query->orderBy('created_at', 'desc')->limit(10); // Limit the logs to the 10 most recent })->embedMap(function (IndexField $field) { $field->text('title'); $field->text('ip'); $field->array('log_data'); }); }); }
IndexField
Methods
Section titled “IndexField Methods”Field types:
Section titled “Field types:”text($field)
integer($field)
array($field)
bool($field)
type($field, $type)
- Set own type (like Enums)embedsMany($field, $relatedModelClass, $whereRelatedField, $equalsLocalField, $query)
embedsBelongTo($field, $relatedModelClass, $whereRelatedField, $equalsLocalField, $query)
embedsOne($field, $relatedModelClass, $whereRelatedField, $equalsLocalField, $query)
Embedded field type methods:
Section titled “Embedded field type methods:”embedMap(function (IndexField $field) {})
- Define the mapping for the embedded relationshipdontObserve()
- Don’t observe changes in the$relatedModelClass