Extending the Search Index
Adding Custom Fields via Events
The index update process stores system fields and supported data object/asset field types by default. Extend the index with custom attributes using the following events.
UpdateIndexDataEvent
Store additional fields in the search index. Use the event matching your element type:
Pimcore\Bundle\GenericDataIndexBundle\Event\Asset\UpdateIndexDataEvent(assets)Pimcore\Bundle\GenericDataIndexBundle\Event\DataObject\UpdateIndexDataEvent(concrete data objects)Pimcore\Bundle\GenericDataIndexBundle\Event\DataObject\UpdateFolderIndexDataEvent(data object folders)Pimcore\Bundle\GenericDataIndexBundle\Event\Document\UpdateIndexDataEvent(documents)
An indexed document in the search index has this structure:
{
"system_fields": {
"id": 145,
"creationDate": "2019-05-24T15:42:20+0200",
"modificationDate": "2019-08-23T15:15:54+0200",
"type": "image",
"key": "abandoned-automobile-automotive-1082654.jpg"
},
"standard_fields": [ ... ],
"custom_fields": [ ]
}
The three sections are:
- system_fields - Base fields common to all elements (id, creationDate, fullPath, etc.)
- standard_fields - Data object fields or asset metadata supported out of the box
- custom_fields - Custom data added via
UpdateIndexDataEvent. Added fields are automatically included in full text search (depending on mapping).
ExtractMappingEvent
Define the search engine mapping for custom fields (see Elasticsearch mapping types or OpenSearch field types). Use the event matching your element type:
Pimcore\Bundle\GenericDataIndexBundle\Event\Asset\ExtractMappingEvent(assets)Pimcore\Bundle\GenericDataIndexBundle\Event\DataObject\ExtractMappingEvent(concrete data objects)Pimcore\Bundle\GenericDataIndexBundle\Event\DataObject\ExtractFolderMappingEvent(data object folders)Pimcore\Bundle\GenericDataIndexBundle\Event\Document\ExtractMappingEvent(documents)
Example 1: Asset File Size Category
This event subscriber categorizes assets by file size into small (< 300 KB),
medium (300 KB - 3 MB), and big (> 3 MB):
<?php
namespace App\EventListener;
use Pimcore\Bundle\GenericDataIndexBundle\Event\Asset\ExtractMappingEvent;
use Pimcore\Bundle\GenericDataIndexBundle\Event\Asset\UpdateIndexDataEvent;
use Pimcore\Model\Asset\Folder;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class FileSizeIndexSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
UpdateIndexDataEvent::class => 'onUpdateIndexData',
ExtractMappingEvent::class => 'onExtractMapping',
];
}
public function onUpdateIndexData(UpdateIndexDataEvent $event): void
{
$asset = $event->getElement();
if ($asset instanceof Folder) {
return;
}
$customFields = $event->getCustomFields();
$fileSize = $asset->getFileSize();
$customFields['fileSizeSelection'] = match (true) {
$fileSize < 300_000 => 'small',
$fileSize <= 3_000_000 => 'medium',
default => 'big',
};
$event->setCustomFields($customFields);
}
public function onExtractMapping(ExtractMappingEvent $event): void
{
$customFieldsMapping = $event->getCustomFieldsMapping();
// 'keyword' works well for select and multi-select filters
$customFieldsMapping['fileSizeSelection'] = [
'type' => 'keyword'
];
$event->setCustomFieldsMapping($customFieldsMapping);
}
}
# config/services.yaml
services:
_defaults:
autowire: true
App\EventListener\FileSizeIndexSubscriber:
tags:
- { name: kernel.event_subscriber }
Example 2: Data Object Variant Count
This event subscriber adds a numberOfVariants field to Car data objects,
counting direct children (variants) of each car:
<?php
namespace App\EventListener;
use Pimcore\Bundle\GenericDataIndexBundle\Event\DataObject\ExtractMappingEvent;
use Pimcore\Bundle\GenericDataIndexBundle\Event\DataObject\UpdateIndexDataEvent;
use Pimcore\Model\DataObject\Car;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CarVariantCountSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
UpdateIndexDataEvent::class => 'onUpdateIndexData',
ExtractMappingEvent::class => 'onExtractMapping',
];
}
public function onUpdateIndexData(UpdateIndexDataEvent $event): void
{
$car = $event->getElement();
if (!$car instanceof Car) {
return;
}
$customFields = $event->getCustomFields();
$customFields['numberOfVariants'] = count($car->getChildren() ?? []);
$event->setCustomFields($customFields);
}
public function onExtractMapping(ExtractMappingEvent $event): void
{
if ($event->getClassDefinition()->getId() !== 'CAR') {
return;
}
$customFieldsMapping = $event->getCustomFieldsMapping();
$customFieldsMapping['numberOfVariants'] = [
'type' => 'integer'
];
$event->setCustomFieldsMapping($customFieldsMapping);
}
}
Rebuild Index After Changes
After registering an event subscriber, rebuild the search index:
bin/console generic-data-index:update:index -r