Skip to content
Permalink
Browse files

EZP-27227: Implement index-time boosting (#90)

* Make text dynamic field multivalued with norms

* Extract UpdateSerializer out of Native Gateway

* Inmplement BoostFactorProvider with tests

* Configure UpdateSerializer in service container

* Configure BoostFactorProvider in service container

* Implement boost factor semantic configuration

* Refactor full-text field indexing

* Remove full-text copy field from schema

* Implement translated Content name field mapper

* Update Fulltext criterion to use new full-text field

* Add test cases for ambiguous mapping resolution

* Boost only text type Content fields

* Fix CS

* TMP: test with kernel branch index-time-boost

* Remove version annotation from file docblocks

* Expand configuration description

* Add BoostFactorProviderFactory class docblock

* Revert "TMP: test with kernel branch index-time-boost"

This reverts commit 74d28f6.

* [Composer] Update kernel requriment for multivalued text field change introudced in 6.7.4/6.9.1
  • Loading branch information...
pspanja authored and andrerom committed May 19, 2017
1 parent 96e09ea commit be8cb5de63851d489d1bfb93bdb4671b844f21cf
@@ -0,0 +1,67 @@
<?php
/**
* This file is part of the eZ Platform Solr Search Engine package.
*
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace EzSystems\EzPlatformSolrSearchEngineBundle\ApiLoader;
use eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* BoostFactorProvider service factory takes into account boost factor semantic configuration.
*/
class BoostFactorProviderFactory implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* @var \eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider
*/
private $repositoryConfigurationProvider;
/**
* @var string
*/
private $defaultConnection;
/**
* @var string
*/
private $boostFactorProviderClass;
/**
* @param \eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider $repositoryConfigurationProvider
* @param string $defaultConnection
* @param string $boostFactorProviderClass
*/
public function __construct(
RepositoryConfigurationProvider $repositoryConfigurationProvider,
$defaultConnection,
$boostFactorProviderClass
) {
$this->repositoryConfigurationProvider = $repositoryConfigurationProvider;
$this->defaultConnection = $defaultConnection;
$this->boostFactorProviderClass = $boostFactorProviderClass;
}
public function buildService()
{
$repositoryConfig = $this->repositoryConfigurationProvider->getRepositoryConfig();
$connection = $this->defaultConnection;
if (isset($repositoryConfig['search']['connection'])) {
$connection = $repositoryConfig['search']['connection'];
}
return new $this->boostFactorProviderClass(
$this->container->getParameter(
"ez_search_engine_solr.connection.{$connection}.boost_factor_map_id"
)
);
}
}
@@ -30,6 +30,11 @@ class Configuration implements ConfigurationInterface
'path' => '/solr',
);
protected $metaFieldNames = [
'name',
'text',
];
public function __construct($rootNodeName)
{
$this->rootNodeName = $rootNodeName;
@@ -94,6 +99,8 @@ protected function addEndpointsSection(ArrayNodeDefinition $node)
/**
* Adds connections definition.
*
* @throws \RuntimeException
*
* @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
*/
protected function addConnectionsSection(ArrayNodeDefinition $node)
@@ -241,6 +248,118 @@ function ($v) {
->end()
->end()
->end()
->arrayNode('boost_factors')
->addDefaultsIfNotSet()
->info(
"Index-time field boost factor mapping.\n\n" .
'Note: Changes to this configuration are not reflected on the Solr index without ' .
'manually re-indexing the affected content or executing a full re-index. ' .
'To avoid that a future version might apply boost factors on the query instead ' .
'(also known as query-time boost).'
)
->children()
->arrayNode('content_type')
->info('A map of ContentType identifiers and boost factors for fields.')
->example(
[
'article' => 1.5,
'blog_post' => 3.0,
]
)
->normalizeKeys(false)
->useAttributeAsKey('content_type_identifier')
->prototype('float')->end()
->end()
->arrayNode('field_definition')
->info('A map of ContentType and/or FieldDefinition identifiers and boost factors for fields.')
->example(
[
'name' => 2.0,
'title' => 1.5,
'blog_post' => [
'title' => 3.0,
],
]
)
->normalizeKeys(false)
->useAttributeAsKey('content_type_identifier')
->beforeNormalization()
->always(
function (array $v) {
$valuesMapped = [];
foreach ($v as $key => $value) {
if (is_array($value)) {
$valuesMapped[$key] = $value;
} else {
$valuesMapped['*'][$key] = $value;
}
}
return $valuesMapped;
}
)
->end()
->prototype('array')
->normalizeKeys(false)
->useAttributeAsKey('field_definition_identifier')
->prototype('float')->end()
->end()
->end()
->arrayNode('meta_field')
->info('A map of ContentType and/or field name identifiers and boost factors for meta fields.')
->example(
[
'name' => 2.0,
'text' => 1.5,
'blog_post' => [
'name' => 3.0,
'text' => 4.0,
],
]
)
->normalizeKeys(false)
->useAttributeAsKey('content_type_identifier')
->beforeNormalization()
->always(
function (array $v) {
$valuesMapped = [];
foreach ($v as $key => $value) {
if (is_array($value)) {
$valuesMapped[$key] = $value;
} else {
$valuesMapped['*'][$key] = $value;
}
}
return $valuesMapped;
}
)
->end()
->prototype('array')
->normalizeKeys(false)
->useAttributeAsKey('meta_field_name')
->validate()
->ifTrue(
function (array $v) {
foreach (array_keys($v) as $key) {
if (!in_array($key, $this->metaFieldNames, true)) {
return true;
}
}
return false;
}
)
->thenInvalid(
'Allowed meta field names are: ' .
implode(', ', $this->metaFieldNames)
)
->end()
->prototype('float')->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end();
@@ -10,6 +10,7 @@
*/
namespace EzSystems\EzPlatformSolrSearchEngineBundle\DependencyInjection;
use EzSystems\EzPlatformSolrSearchEngine\FieldMapper\BoostFactorProvider;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
@@ -68,6 +69,11 @@ class EzSystemsEzPlatformSolrSearchEngineExtension extends Extension
*/
const ENDPOINT_TAG = 'ezpublish.search.solr.endpoint';
/**
* @var string
*/
const BOOST_FACTOR_PROVIDER_ID = 'ezpublish.search.solr.field_mapper.boost_factor_provider';
public function getAlias()
{
return 'ez_search_engine_solr';
@@ -111,7 +117,7 @@ public function load(array $configs, ContainerBuilder $container)
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
* @param array $config
*/
protected function processConnectionConfiguration(ContainerBuilder $container, $config)
protected function processConnectionConfiguration(ContainerBuilder $container, array $config)
{
$alias = $this->getAlias();
@@ -130,6 +136,7 @@ protected function processConnectionConfiguration(ContainerBuilder $container, $
foreach ($config['connections'] as $name => $params) {
$this->configureSearchServices($container, $name, $params);
$this->configureBoostMap($container, $name, $params);
$container->setParameter("$alias.connection.$name", $params);
}
@@ -140,6 +147,10 @@ protected function processConnectionConfiguration(ContainerBuilder $container, $
// Search engine itself, for given connection name
$searchEngineDef = $container->findDefinition(self::ENGINE_ID);
$searchEngineDef->setFactory([new Reference('ezpublish.solr.engine_factory'), 'buildEngine']);
// Factory for BoostFactorProvider uses mapping configured for the connection in use
$boostFactorProviderDef = $container->findDefinition(self::BOOST_FACTOR_PROVIDER_ID);
$boostFactorProviderDef->setFactory([new Reference('ezpublish.solr.boost_factor_provider_factory'), 'buildService']);
}
/**
@@ -175,6 +186,22 @@ private function configureSearchServices(ContainerBuilder $container, $connectio
$container->setDefinition($gatewayId, $gatewayDefinition);
}
/**
* Creates boost factor map parameter for a given $connectionName.
*
* @param ContainerBuilder $container
* @param string $connectionName
* @param array $connectionParams
*/
private function configureBoostMap(ContainerBuilder $container, $connectionName, $connectionParams)
{
$alias = $this->getAlias();
$boostFactorMap = $this->buildBoostFactorMap($connectionParams['boost_factors']);
$boostFactorMapId = "{$alias}.connection.{$connectionName}.boost_factor_map_id";
$container->setParameter($boostFactorMapId, $boostFactorMap);
}
/**
* Creates Endpoint definition in the service container.
*
@@ -197,4 +224,37 @@ public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->getAlias());
}
/**
* Builds boost factor map from the given $config.
*
* @see \EzSystems\EzPlatformSolrSearchEngine\FieldMapper\BoostFactorProvider::$map
*
* @param array $config
*
* @return array
*/
protected function buildBoostFactorMap(array $config)
{
$boostFactorMap = [];
foreach ($config['content_type'] as $typeIdentifier => $factor) {
$boostFactorMap['content-fields'][$typeIdentifier]['*'] = $factor;
$boostFactorMap['meta-fields'][$typeIdentifier]['*'] = $factor;
}
foreach ($config['field_definition'] as $typeIdentifier => $mapping) {
foreach ($mapping as $fieldIdentifier => $factor) {
$boostFactorMap['content-fields'][$typeIdentifier][$fieldIdentifier] = $factor;
}
}
foreach ($config['meta_field'] as $typeIdentifier => $mapping) {
foreach ($mapping as $fieldIdentifier => $factor) {
$boostFactorMap['meta-fields'][$typeIdentifier][$fieldIdentifier] = $factor;
}
}
return $boostFactorMap;
}
}
@@ -1,5 +1,6 @@
parameters:
ezpublish.solr.engine_factory.class: EzSystems\EzPlatformSolrSearchEngineBundle\ApiLoader\SolrEngineFactory
ezpublish.solr.boost_factor_provider_factory.class: EzSystems\EzPlatformSolrSearchEngineBundle\ApiLoader\BoostFactorProviderFactory
ez_search_engine_solr.default_connection: ~

services:
@@ -11,3 +12,12 @@ services:
- "%ezpublish.spi.search.solr.class%"
calls:
- [setContainer, ["@service_container"]]

ezpublish.solr.boost_factor_provider_factory:
class: "%ezpublish.solr.boost_factor_provider_factory.class%"
arguments:
- "@ezpublish.api.repository_configuration_provider"
- "%ez_search_engine_solr.default_connection%"
- "%ezpublish.search.solr.boost_factor_provider.class%"
calls:
- [setContainer, ["@service_container"]]
@@ -12,7 +12,7 @@
],
"require": {
"php": "~5.6|~7.0",
"ezsystems/ezpublish-kernel": "^6.7.0@dev|^7.0@dev"
"ezsystems/ezpublish-kernel": "~6.7.4@dev|^6.9.1@dev|^7.0@dev"
},
"require-dev": {
"phpunit/phpunit": "~4.7",
Oops, something went wrong.

0 comments on commit be8cb5d

Please sign in to comment.
You can’t perform that action at this time.