diff --git a/databox/api/config/packages/fos_elastica.yaml b/databox/api/config/packages/fos_elastica.yaml index 6c4ed1c09..63fa7d1dc 100644 --- a/databox/api/config/packages/fos_elastica.yaml +++ b/databox/api/config/packages/fos_elastica.yaml @@ -68,7 +68,7 @@ fos_elastica: analyzer: partial_words search_analyzer: text term_vector: with_positions_offsets - attributes: + !php/const App\Attribute\AttributeInterface::ATTRIBUTES_FIELD: type: object referenceCollectionId: type: keyword diff --git a/databox/api/config/services.yaml b/databox/api/config/services.yaml index 6e28f85a4..c02681174 100644 --- a/databox/api/config/services.yaml +++ b/databox/api/config/services.yaml @@ -67,10 +67,6 @@ services: $signingKey: '%env(APP_SECRET)%' $ttl: 86400 - App\Elasticsearch\Mapping\IndexMappingUpdater: - arguments: - $index: '@fos_elastica.index.asset' - App\Elasticsearch\Mapping\ElasticsearchClient: arguments: $client: '@fos_elastica.client' diff --git a/databox/api/src/Attribute/AttributeInterface.php b/databox/api/src/Attribute/AttributeInterface.php index 4ec7dc5a3..674075f99 100644 --- a/databox/api/src/Attribute/AttributeInterface.php +++ b/databox/api/src/Attribute/AttributeInterface.php @@ -4,6 +4,6 @@ interface AttributeInterface { - final public const ATTRIBUTES_FIELD = 'attributes'; + final public const ATTRIBUTES_FIELD = 'attrs'; final public const NO_LOCALE = '_'; } diff --git a/databox/api/src/Attribute/AttributeLocaleInterface.php b/databox/api/src/Attribute/AttributeLocaleInterface.php new file mode 100644 index 000000000..a1dd4c4bf --- /dev/null +++ b/databox/api/src/Attribute/AttributeLocaleInterface.php @@ -0,0 +1,46 @@ + 'arabic', + 'bg' => 'bulgarian', + 'bn' => 'bengali', + 'ca' => 'catalan', + 'ch' => 'cjk', + 'ckb' => 'sorani', + 'cs' => 'czech', + 'da' => 'danish', + 'de' => 'german', + 'el' => 'greek', + 'en' => 'english', + 'es' => 'spanish', + 'et' => 'estonian', + 'eu' => 'basque', + 'fa' => 'persian', + 'fi' => 'finnish', + 'fr' => 'french', + 'ga' => 'irish', + 'gl' => 'galician', + 'hi' => 'hindi', + 'hu' => 'hungarian', + 'hy' => 'armenian', + 'id' => 'indonesian', + 'it' => 'italian', + 'ja' => 'cjk', + 'ko' => 'cjk', + 'lt' => 'lithuanian', + 'lv' => 'latvian', + 'nl' => 'dutch', + 'no' => 'norwegian', + 'pt' => 'portuguese', + 'pt_BR' => 'brazilian', + 'ro' => 'romanian', + 'ru' => 'russian', + 'sv' => 'swedish', + 'th' => 'thai', + 'tr' => 'turkish', + ]; +} diff --git a/databox/api/src/Attribute/Type/AbstractAttributeType.php b/databox/api/src/Attribute/Type/AbstractAttributeType.php index 23665d541..5efbcef0f 100644 --- a/databox/api/src/Attribute/Type/AbstractAttributeType.php +++ b/databox/api/src/Attribute/Type/AbstractAttributeType.php @@ -48,6 +48,11 @@ public function getFacetType(): string return ESFacetInterface::TYPE_TEXT; } + public function isMappingLocaleAware(): bool + { + return false; + } + public function isLocaleAware(): bool { return false; @@ -72,7 +77,7 @@ public function getGroupValueLabel($value): ?string return (string) $value; } - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array + public function getElasticSearchMapping(string $locale): ?array { return []; } diff --git a/databox/api/src/Attribute/Type/AttributeTypeInterface.php b/databox/api/src/Attribute/Type/AttributeTypeInterface.php index cd3ac81ef..6cd410834 100644 --- a/databox/api/src/Attribute/Type/AttributeTypeInterface.php +++ b/databox/api/src/Attribute/Type/AttributeTypeInterface.php @@ -31,7 +31,7 @@ public function createFilterQuery(string $field, $value): AbstractQuery; public function supportsAggregation(): bool; - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array; + public function getElasticSearchMapping(string $locale): ?array; /** * Normalize value for database. @@ -58,6 +58,7 @@ public function denormalizeElasticsearchValue(mixed $value): ?string; */ public function normalizeElasticsearchValue(?string $value); + public function isMappingLocaleAware(): bool; public function isLocaleAware(): bool; public function supportsSuggest(): bool; diff --git a/databox/api/src/Attribute/Type/CodeAttributeType.php b/databox/api/src/Attribute/Type/CodeAttributeType.php index 0712884d5..f306181d5 100644 --- a/databox/api/src/Attribute/Type/CodeAttributeType.php +++ b/databox/api/src/Attribute/Type/CodeAttributeType.php @@ -10,4 +10,9 @@ public static function getName(): string { return 'code'; } + + public function isMappingLocaleAware(): bool + { + return false; + } } diff --git a/databox/api/src/Attribute/Type/CollectionPathAttributeType.php b/databox/api/src/Attribute/Type/CollectionPathAttributeType.php index 59884849c..5115d0893 100644 --- a/databox/api/src/Attribute/Type/CollectionPathAttributeType.php +++ b/databox/api/src/Attribute/Type/CollectionPathAttributeType.php @@ -56,9 +56,9 @@ public function createFilterQuery(string $field, $value): AbstractQuery return new Query\Terms($field, $value); } - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array + public function getElasticSearchMapping(string $locale): ?array { - throw new \LogicException('Should never be called'); + return null; } public function isLocaleAware(): bool diff --git a/databox/api/src/Attribute/Type/DateTimeAttributeType.php b/databox/api/src/Attribute/Type/DateTimeAttributeType.php index c01f93042..d9af6f470 100644 --- a/databox/api/src/Attribute/Type/DateTimeAttributeType.php +++ b/databox/api/src/Attribute/Type/DateTimeAttributeType.php @@ -66,7 +66,7 @@ public function getElasticSearchType(): string return 'date'; } - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array + public function getElasticSearchMapping(string $locale): ?array { return [ 'fields' => [ diff --git a/databox/api/src/Attribute/Type/EntityAttributeType.php b/databox/api/src/Attribute/Type/EntityAttributeType.php index 7d57ca7e6..531d1061f 100644 --- a/databox/api/src/Attribute/Type/EntityAttributeType.php +++ b/databox/api/src/Attribute/Type/EntityAttributeType.php @@ -109,20 +109,20 @@ public function denormalizeValue(?string $value): ?array ]; } - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array + public function getElasticSearchMapping(string $locale): ?array { - $mapping = parent::getElasticSearchMapping($locale, $definition); + $mapping = parent::getElasticSearchMapping($locale); return [ 'type' => 'object', 'properties' => [ + 'id' => [ + 'type' => 'keyword', + ], 'value' => [ ...$mapping, 'type' => $this->getElasticSearchType(), ], - 'id' => [ - 'type' => 'keyword', - ], ], ]; } diff --git a/databox/api/src/Attribute/Type/NumberAttributeType.php b/databox/api/src/Attribute/Type/NumberAttributeType.php index 6614d50b3..7cbbb0cb3 100644 --- a/databox/api/src/Attribute/Type/NumberAttributeType.php +++ b/databox/api/src/Attribute/Type/NumberAttributeType.php @@ -19,7 +19,7 @@ public static function getName(): string return self::NAME; } - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array + public function getElasticSearchMapping(string $locale): ?array { return [ 'fields' => [ diff --git a/databox/api/src/Attribute/Type/TextAttributeType.php b/databox/api/src/Attribute/Type/TextAttributeType.php index 9494df656..b98c7cf86 100644 --- a/databox/api/src/Attribute/Type/TextAttributeType.php +++ b/databox/api/src/Attribute/Type/TextAttributeType.php @@ -5,6 +5,7 @@ namespace App\Attribute\Type; use Alchemy\CoreBundle\Util\LocaleUtil; +use App\Attribute\AttributeLocaleInterface; use App\Elasticsearch\SearchType; use App\Entity\Core\AttributeDefinition; use Elastica\Query; @@ -40,66 +41,22 @@ public function createFilterQuery(string $field, $value): AbstractQuery return new Query\Terms($field, $value); } - public function getElasticSearchMapping(string $locale, AttributeDefinition $definition): array + public function getElasticSearchMapping(string $locale): ?array { - $mapping = []; - - if (true - // TODO Should always provision keyword? - || $definition->isFacetEnabled()) { - $mapping['fields'] = [ + $mapping = [ + 'fields' => [ 'raw' => [ 'type' => 'keyword', - 'ignore_above' => 500, + 'ignore_above' => 256, ], - ]; - } - - $locales = [ - 'ar' => 'arabic', - 'bg' => 'bulgarian', - 'bn' => 'bengali', - 'ca' => 'catalan', - 'ch' => 'cjk', - 'ckb' => 'sorani', - 'cs' => 'czech', - 'da' => 'danish', - 'de' => 'german', - 'el' => 'greek', - 'en' => 'english', - 'es' => 'spanish', - 'et' => 'estonian', - 'eu' => 'basque', - 'fa' => 'persian', - 'fi' => 'finnish', - 'fr' => 'french', - 'ga' => 'irish', - 'gl' => 'galician', - 'hi' => 'hindi', - 'hu' => 'hungarian', - 'hy' => 'armenian', - 'id' => 'indonesian', - 'it' => 'italian', - 'ja' => 'cjk', - 'ko' => 'cjk', - 'lt' => 'lithuanian', - 'lv' => 'latvian', - 'nl' => 'dutch', - 'no' => 'norwegian', - 'pt' => 'portuguese', - 'pt_BR' => 'brazilian', - 'ro' => 'romanian', - 'ru' => 'russian', - 'sv' => 'swedish', - 'th' => 'thai', - 'tr' => 'turkish', + ], ]; $language = LocaleUtil::extractLanguageFromLocale($locale); - if (isset($locales[$locale])) { - $mapping['analyzer'] = $locales[$locale]; - } elseif (isset($locales[$language])) { - $mapping['analyzer'] = $locales[$language]; + if (isset(AttributeLocaleInterface::LOCALES[$locale])) { + $mapping['analyzer'] = AttributeLocaleInterface::LOCALES[$locale]; + } elseif (isset(AttributeLocaleInterface::LOCALES[$language])) { + $mapping['analyzer'] = AttributeLocaleInterface::LOCALES[$language]; } else { $mapping['analyzer'] = 'text'; } @@ -107,6 +64,11 @@ public function getElasticSearchMapping(string $locale, AttributeDefinition $def return $mapping; } + public function isMappingLocaleAware(): bool + { + return $this->isLocaleAware(); + } + public function isLocaleAware(): bool { return true; diff --git a/databox/api/src/Command/SynchronizeESMappingCommand.php b/databox/api/src/Command/SynchronizeESMappingCommand.php deleted file mode 100644 index 142f07fee..000000000 --- a/databox/api/src/Command/SynchronizeESMappingCommand.php +++ /dev/null @@ -1,58 +0,0 @@ -setName('app:search:sync-mapping') - ->setDescription('Synchronize Elasticsearch mapping with attribute definitions') - ->addArgument('workspace', InputArgument::REQUIRED) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $q = $this->em->createNativeQuery(' - SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.locale AS locale_1, a0_.position AS position_2, a0_.value AS value_3, a0_.created_at AS created_at_4, a0_.updated_at AS updated_at_5, a0_.locked AS locked_6, a0_.translation_id AS translation_id_7, a0_.translation_origin_hash AS translation_origin_hash_8, a0_.origin AS origin_9, a0_.origin_vendor AS origin_vendor_10, a0_.origin_user_id AS origin_user_id_11, a0_.origin_vendor_context AS origin_vendor_context_12, a0_.coordinates AS coordinates_13, a0_.status AS status_14, a0_.confidence AS confidence_15 FROM attribute a0_ INNER JOIN attribute_definition a1_ ON a0_.definition_id = a1_.id WHERE a1_.field_type IN (1,2) ORDER BY a0_.asset_id ASC, a0_.id ASC) dctrn_result) dctrn_table - ', new ResultSetMapping()); - $q->getResult(); - - throw new \InvalidArgumentException(sprintf('OK')); - - $workspaceId = $input->getArgument('workspace'); - $workspace = $this->em->find(Workspace::class, $workspaceId); - - if (!$workspace instanceof Workspace) { - throw new \InvalidArgumentException('Workspace '.$workspaceId.' not found'); - } - - $this->indexMappingUpdater->synchronizeWorkspace($workspace); - - $output->writeln('Done.'); - - return 0; - } -} diff --git a/databox/api/src/Consumer/Handler/Search/Mapping/UpdateAttributesMapping.php b/databox/api/src/Consumer/Handler/Search/Mapping/UpdateAttributesMapping.php deleted file mode 100644 index b9adeefc0..000000000 --- a/databox/api/src/Consumer/Handler/Search/Mapping/UpdateAttributesMapping.php +++ /dev/null @@ -1,18 +0,0 @@ -id; - } -} diff --git a/databox/api/src/Consumer/Handler/Search/Mapping/UpdateAttributesMappingHandler.php b/databox/api/src/Consumer/Handler/Search/Mapping/UpdateAttributesMappingHandler.php deleted file mode 100644 index 6984a8dd4..000000000 --- a/databox/api/src/Consumer/Handler/Search/Mapping/UpdateAttributesMappingHandler.php +++ /dev/null @@ -1,29 +0,0 @@ -em, Workspace::class, $message->getId()); - - $this->indexMappingUpdater->synchronizeWorkspace($workspace); - } -} diff --git a/databox/api/src/Doctrine/Listener/AttributeMappingListener.php b/databox/api/src/Doctrine/Listener/AttributeMappingListener.php deleted file mode 100644 index 448038465..000000000 --- a/databox/api/src/Doctrine/Listener/AttributeMappingListener.php +++ /dev/null @@ -1,70 +0,0 @@ -getObject(); - - if ($entity instanceof Workspace) { - if ($this->hasChangedField([ - 'enabledLocales', - ], $args->getObjectManager(), $entity)) { - $this->updateWorkspace($entity->getId()); - } - } elseif ($entity instanceof AttributeDefinition) { - if ($this->hasChangedField([ - 'fieldType', - 'name', - 'searchable', - 'suggest', - ], $args->getObjectManager(), $entity)) { - $this->updateWorkspace($entity->getWorkspaceId()); - } - } - } - - public function postPersist(PostPersistEventArgs $args): void - { - $entity = $args->getObject(); - - if ($entity instanceof AttributeDefinition) { - $this->updateWorkspace($entity->getWorkspaceId()); - } - } - - public function updateWorkspace(string $workspaceId): void - { - $this->postFlushStack->addBusMessage(new UpdateAttributesMapping($workspaceId)); - } - - public function getSubscribedEvents(): array - { - return [ - Events::postUpdate, - Events::postPersist, - ]; - } -} diff --git a/databox/api/src/Elasticsearch/Listener/PostIndexMappingListener.php b/databox/api/src/Elasticsearch/Listener/PostIndexMappingListener.php index 7d4a290f7..7b95a7065 100644 --- a/databox/api/src/Elasticsearch/Listener/PostIndexMappingListener.php +++ b/databox/api/src/Elasticsearch/Listener/PostIndexMappingListener.php @@ -4,18 +4,14 @@ namespace App\Elasticsearch\Listener; -use App\Elasticsearch\Mapping\IndexMappingUpdater; -use App\Entity\Core\AttributeDefinition; -use App\Entity\Core\Workspace; -use Doctrine\ORM\EntityManagerInterface; +use App\Elasticsearch\Mapping\IndexMappingTemplatesMaker; use FOS\ElasticaBundle\Event\PostIndexMappingBuildEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; readonly class PostIndexMappingListener implements EventSubscriberInterface { public function __construct( - private EntityManagerInterface $em, - private IndexMappingUpdater $indexMappingUpdater, + private IndexMappingTemplatesMaker $indexMappingUpdater, ) { } @@ -26,19 +22,7 @@ public function configureIndex(PostIndexMappingBuildEvent $event): void } $mapping = $event->getMapping(); - - $workspaces = $this->em->getRepository(Workspace::class)->findAll(); - foreach ($workspaces as $workspace) { - /** @var AttributeDefinition[] $attributeDefinitions */ - $attributeDefinitions = $this->em->getRepository(AttributeDefinition::class) - ->findBy([ - 'workspace' => $workspace->getId(), - ]); - - foreach ($attributeDefinitions as $definition) { - $this->indexMappingUpdater->assignAttributeDefinitionToMapping($mapping, $definition); - } - } + $mapping['dynamic_templates'] = $this->indexMappingUpdater->getAssetDynamicTemplates(); $event->setMapping($mapping); } diff --git a/databox/api/src/Elasticsearch/Mapping/FieldNameResolver.php b/databox/api/src/Elasticsearch/Mapping/FieldNameResolver.php index e6651d882..f3131444c 100644 --- a/databox/api/src/Elasticsearch/Mapping/FieldNameResolver.php +++ b/databox/api/src/Elasticsearch/Mapping/FieldNameResolver.php @@ -29,11 +29,16 @@ public function getFieldName(string $slug, string $fieldType, bool $isMultiple): return sprintf('%s_%s_%s', $slug, - str_replace('_', '-', $type::getName()), + $this->normalizeTypeNameForField($type::getName()), $isMultiple ? 'm' : 's' ); } + public function normalizeTypeNameForField(string $type): string + { + return str_replace('_', '-', $type); + } + /** * @return array{field: string, type: AttributeTypeInterface} */ diff --git a/databox/api/src/Elasticsearch/Mapping/IndexMappingTemplatesMaker.php b/databox/api/src/Elasticsearch/Mapping/IndexMappingTemplatesMaker.php new file mode 100644 index 000000000..dbf98179e --- /dev/null +++ b/databox/api/src/Elasticsearch/Mapping/IndexMappingTemplatesMaker.php @@ -0,0 +1,85 @@ +attributeTypeRegistry->getTypes() as $type) { + $field = $this->fieldNameResolver->normalizeTypeNameForField($type::getName()); + + if ($type->isMappingLocaleAware()) { + foreach ($locales as $locale) { + $mapping = $this->getTypeMapping($type, $locale); + if (null !== $mapping) { + $templates[] = [ + 't_'.$type::getName().'_'.$locale => [ + 'match_pattern' => 'regex', + 'path_match' => sprintf('^%s\.%s\..+_%s_[sm]$', + AttributeInterface::ATTRIBUTES_FIELD, + $locale, + $field + ), + 'mapping' => $mapping, + ], + ]; + } + } + } else { + $mapping = $this->getTypeMapping($type, AttributeInterface::NO_LOCALE); + if (null !== $mapping) { + $templates[] = [ + 't_'.$type::getName() => [ + 'match_pattern' => 'regex', + 'path_match' => sprintf('^%s\.[^.]+\..+_%s_[sm]$', + AttributeInterface::ATTRIBUTES_FIELD, + $field + ), + 'mapping' => $mapping, + ], + ]; + } + } + } + + return $templates; + } + + private function getTypeMapping(AttributeTypeInterface $type, string $locale): ?array + { + $typeMapping = $type->getElasticSearchMapping($locale); + if (null === $typeMapping) { + return null; + } + + $mapping = array_merge([ + 'type' => $type->getElasticSearchType(), + ], $typeMapping); + + if (in_array($mapping['type'], [ + 'object', + 'nested', + ], true)) { + unset($mapping['meta']); + } + + return $mapping; + } +} diff --git a/databox/api/src/Elasticsearch/Mapping/IndexMappingUpdater.php b/databox/api/src/Elasticsearch/Mapping/IndexMappingUpdater.php deleted file mode 100644 index d352f5664..000000000 --- a/databox/api/src/Elasticsearch/Mapping/IndexMappingUpdater.php +++ /dev/null @@ -1,139 +0,0 @@ -fieldNameResolver->getFieldNameFromDefinition($definition); - $mapping['properties'][AttributeInterface::ATTRIBUTES_FIELD] ??= [ - 'type' => 'object', - 'properties' => [], - ]; - - $properties = &$mapping['properties'][AttributeInterface::ATTRIBUTES_FIELD]['properties']; - - $properties[$locale] ??= [ - 'type' => 'object', - 'properties' => [], - ]; - - $lProps = &$properties[$locale]['properties']; - - $lProps[$fieldName] = $this->getFieldMapping($definition, $locale); - } - - private function getFieldMapping(AttributeDefinition $definition, string $locale): array - { - $type = $this->attributeTypeRegistry->getStrictType($definition->getFieldType()); - - $mapping = array_merge([ - 'type' => $type->getElasticSearchType(), - 'meta' => [ - 'attribute_id' => $definition->getId(), - 'attribute_name' => $definition->getName(), - ], - ], $type->getElasticSearchMapping($locale, $definition)); - - if (in_array($mapping['type'], [ - 'object', - 'nested', - ], true)) { - unset($mapping['meta']); - } - - return $mapping; - } - - public function synchronizeWorkspace(Workspace $workspace): void - { - $mapping = $this->index->getMapping(); - - $attributes = $mapping['properties'][AttributeInterface::ATTRIBUTES_FIELD]['properties'] ?? []; - - $newMapping = [ - 'properties' => [ - AttributeInterface::ATTRIBUTES_FIELD => [ - 'type' => 'object', - 'properties' => [], - ], - ], - ]; - - /** @var AttributeDefinition[] $attributeDefinitions */ - $attributeDefinitions = $this->em->getRepository(AttributeDefinition::class) - ->findBy([ - 'workspace' => $workspace->getId(), - ]); - - foreach ($attributeDefinitions as $definition) { - $this->assignAttributeDefinitionToMapping($newMapping, $definition, $attributes); - } - - $indexName = $this->client->getAliasedIndex($this->index->getName()); - - $this->client->updateMapping($indexName, $newMapping); - } - - public function assignAttributeDefinitionToMapping(array &$newMapping, AttributeDefinition $definition, array $existingAttributes = []): bool - { - $upsert = false; - $fieldName = $this->fieldNameResolver->getFieldNameFromDefinition($definition); - $type = $this->attributeTypeRegistry->getStrictType($definition->getFieldType()); - - $workspace = $definition->getWorkspace(); - - $assign = function (string $locale) use ($existingAttributes, $fieldName, $definition, &$newMapping, &$upsert): void { - if (isset($existingAttributes[$locale][$fieldName])) { - $a = $existingAttributes[$locale][$fieldName]; - - if (!$this->isSameMapping($a, $definition, $locale)) { - $upsert = true; - } - } else { - $upsert = true; - } - - if ($upsert) { - $this->assignAttributeToMapping( - $newMapping, - $locale, - $definition - ); - } - }; - - $assign(AttributeInterface::NO_LOCALE); - if ($type->isLocaleAware() && ($definition->isTranslatable() || $type->supportsTranslations())) { - foreach ($workspace->getEnabledLocales() as $locale) { - $assign($locale); - } - } - - return $upsert; - } - - private function isSameMapping(array $mapping, AttributeDefinition $definition, string $locale): bool - { - return empty(array_diff($mapping, $this->getFieldMapping($definition, $locale))); - } -} diff --git a/databox/api/tests/Attribute/AttributeSearchTest.php b/databox/api/tests/Attribute/AttributeSearchTest.php index ed8735c8a..023ce48f1 100644 --- a/databox/api/tests/Attribute/AttributeSearchTest.php +++ b/databox/api/tests/Attribute/AttributeSearchTest.php @@ -2,6 +2,7 @@ namespace App\Tests\Attribute; +use App\Attribute\AttributeInterface; use App\Attribute\AttributeTypeRegistry; use App\Attribute\Type\TextAttributeType; use App\Elasticsearch\AttributeSearch; @@ -87,7 +88,7 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -111,7 +112,7 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 42, 'fz' => true, @@ -162,12 +163,12 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, ], - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -194,7 +195,7 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -210,7 +211,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -221,7 +222,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 2, 'fz' => true, @@ -243,7 +244,7 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -259,7 +260,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -281,7 +282,7 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -297,7 +298,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -319,12 +320,12 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, ], - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -349,7 +350,7 @@ public function getCases(): array [ [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -360,7 +361,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.title_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.title_text_s' => [ 'st' => SearchType::Match->value, 'b' => 3, 'fz' => true, @@ -371,7 +372,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 1, 'fz' => true, @@ -382,7 +383,7 @@ public function getCases(): array ], [ 'fields' => [ - 'attributes._.desc_text_s' => [ + AttributeInterface::ATTRIBUTES_FIELD.'._.desc_text_s' => [ 'st' => SearchType::Match->value, 'b' => 2, 'fz' => true,