chameleon-system-private/elastic-integration-bundle

Integrates the elastic bundle into chameleon to allow searching/indexing items other than products

8.0.45 2025-12-15 13:48 UTC

README

To create a new list using the ElasticBundle and the ItemListBundle, follow these instructions:

  1. Create your Index/Mapping for the chameleon elastic bundle (see readme in chameleon-system/elastic-bundle) Example:
    chameleon_system_elastic:
      indices:
     my_index_de:
       settings: common
       mappings: ["my_mapping"]
       language: 'de'
     my_index_en:
       settings: common
       mappings: ["my_mapping"]
       language: 'en'
      connection:
     - { host: "%env(string:ESONO_ELASTIC_HOST)%", port:%env(int:ESONO_ELASTIC_PORT)%}
      mappings:
     my_mapping:
       properties:
         name:
           type: text
           analyzer: "index_word_split"
           search_analyzer: "index_word_split"
    ...
    
  2. Create your indexer bei extending \ChameleonSystem\ElasticBundle\Indexer\AbstractIndexer.

  3. Create a service definition for the indexer you just created, tagging it with chameleon_system_elastic.indexer. The tag will need an alias, so you can call a specific indexer via the console. Example:

     <parameters>
         <parameter key="my_index_list" type="collection">
             <parameter>my_index_de</parameter>
             <parameter>my_index_en</parameter>
         </parameter>
     </parameters>
     <service class="MyBundle\MyIndexer"
              id="my_bundle.my_indexer"
              parent="chameleon_system_elastic.indexer.abstract_indexer">
         <!-- We use setter injection since the parent class already has a lot of parameters in its constructor.
              If the constructor of the parent ever changes, the setter injection will not be affected by that change. -->
         <call method="setIndexConfigurationNames">
             <argument>%my_index_list%</argument>
         </call>
         <tag name="chameleon_system_elastic.indexer" alias="my_indexer"/>
     </service>
    

    This will create an indexer named my_indexer which will fill the index my_index_de and my_index_en.

  4. To periodically push changes via cms backend to elastic, add the relevant tables to the re-indexer:

    chameleon_system_elastic_integration:
      reindex:
     # Controls which tables will generate reindex queue entries when being changed via backend.
     tablesToWatch:
       - my_table
     # In order to be able to process a reindex queue entry we need to know which indexers (it may be many) need to react to it. 
     # So we need to map the tables to the aliases defined in the `chameleon_system_elastic.indexer` tag of these indexers.
     tablesToIndexerMapping:
       my_table:
         - my_indexer
    
  5. If you need to add dynamic mappings to your document, you can do so by creating a MappingModifier (implement \ChameleonSystem\Elastic\Interfaces\MappingModifierInterface) and tag with chameleon_system_elastic.mapping_modifier. Add the attribute index to the tag, to select the indices the mapping should apply to. Example:

    <service class="MyBundle\MyMappingModifier" id="my_bundle.mapping_modifier">
     <tag name="chameleon_system_elastic.mapping_modifier" index="my_index_*"/>
    </service>
    
  6. To Search/Filter, you should use the chameleon-system/item-list-bundle. Implement a ListItemProvider (\ChameleonSystem\ItemList\Interfaces\ListItemProviderInterface) Since these providers tend to be very similar, you may consider basing them on \ChameleonSystem\ElasticIntegrationBundle\Bridge\Chameleon\ItemList\AbstractListItemProvider.

  7. Filtering and Sorting: The item list provider will need to interpret the filter and sort definitions you made for the chameleon-system/item-list-bundle. This is done by defining a mapping between the filter definitions for your list and elastic search filter (implementing \ChameleonSystem\ElasticIntegration\Interfaces\FilterAggregationInterface or \ChameleonSystem\ElasticIntegration\Interfaces\FilterInterface) and a mapping between the sort definitions from your list and the elastic search sort options (implementing \ChameleonSystem\Elastic\Interfaces\SortInterface).

Example Mapping for Filter/Sorting using chameleon-system/item-list-bundle:

chameleon_system_item_list:
  filter:
    -
      id: experience
      title: my_theme_bndle.filter.experience_header
      group: somegroup
      view: /filter/experience.html.twig
    -
      id: currency
      title: my_theme_bndle.filter.currency_header
      group: somegroup
      view: /filter/currency.html.twig
  sort:
    -
      id: experience
      title: "my_theme_bndle.sort.experience"
      group: somegroup

chameleon_system_elastic_integration:
  filterServiceMapping:
    -
      group: somegroup
      id: experience
      filterServiceId: my_bundle.filter.experience
    -
      group: somegroup
      id: currency
      filterServiceId: my_bundle.filter.currency
  sortServiceMapping:
    -
      group: somegroup
      id: experience
      sortServiceId: my_bundle.sort.experience

Term Suggest API

If you want to provide term suggestions in a search field, as may make sense if you provide your users with the option to search in specific fields, then you can use the completion suggester api for this.

To use the API, you need to follow these steps:

  1. Create a tree node to provide a URL for the API and assign it to the system page \ChameleonSystem\ElasticIntegrationBundle\ChameleonSystemElasticIntegrationConstants::SYSTEM_PAGE_COMPLETION_SUGGESTER

  2. Set the proper mapping for the field (see https://www.elastic.co/guide/en/elasticsearch/reference/7.9/search-suggesters.html#completion-suggester):

    "suggest": {
      "type": "completion"
    }
    
  3. Create a service for the class \ChameleonSystem\ElasticIntegration\CompletionSuggester\CompletionSuggester and configure it to do completion for your field.

    <service class="ChameleonSystem\ElasticIntegration\CompletionSuggester\CompletionSuggester" id="app.completion_suggester.keywords" public="false">
     <tag name="chameleon_system_elastic_integration.completion_suggester" field="keywords" /> <!-- note the "keywords" here. This will become part of the API URL -->
     <argument type="service" id="chameleon_system_elastic_integration.elastic_helper_collection"/>
     <argument type="service" id="chameleon_system_elastic.search_manager" />
     <argument type="collection"><!-- list of indexes in which to search -->
         <argument>my_index</argument>
     </argument>
     <argument>keywords.suggest</argument><!-- the field configured for completion -->
     <argument type="collection"><!-- list of fields to return on completion. data is currently not used - but elastic wants this anyway. -->
         <argument>keywords</argument>
     </argument>
     <argument>10</argument><!-- number of suggestions to return -->
    </service>
    
  4. Suggestions should now be returned as a json array when you call the API /path-to-system-page/keywords?string=foo