Files

231 lines
7.3 KiB
PHP
Executable File

<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Elastic Search Base for Magento 2
*/
namespace Amasty\ElasticSearch\Model\Adapter\Elasticsearch7;
use Amasty\ElasticSearch\Api\Data\Indexer\Data\DataMapperResolverInterface;
use Amasty\ElasticSearch\Api\Data\Indexer\Structure\IndexBuilderInterface;
use Amasty\ElasticSearch\Model\Adapter\AdapterInterface;
use Amasty\ElasticSearch\Model\Adapter\FieldMappingBuilderInterface;
use Amasty\ElasticSearch\Model\Adapter\Index\IndexNameResolver;
use Amasty\ElasticSearch\Model\Adapter\SaveQueryBuilderInterface;
use Amasty\ElasticSearch\Model\Client\ClientInterface;
use Amasty\ElasticSearch\Model\Client\ClientRepositoryInterface;
use Amasty\ElasticSearch\Model\Debug;
use Amasty\ElasticSearch\Model\Indexer\Structure\EntityBuilder as EntityStructureBuilder;
use Exception;
class Elasticsearch implements AdapterInterface
{
/**
* @var FieldMappingBuilderInterface
*/
private $fieldMappingBuilder;
/**
* @var IndexNameResolver
*/
private $indexNameResolver;
/**
* @var ClientRepositoryInterface
*/
private $clientRepository;
/**
* @var IndexBuilderInterface
*/
private $indexBuilder;
/**
* @var EntityStructureBuilder
*/
private $entityStructureBuilder;
/**
* @var DataMapperResolverInterface
*/
private $dataMapperResolver;
/**
* @var SaveQueryBuilderInterface
*/
private $saveQueryBuilder;
/**
* @var Debug
*/
private $debug;
/**
* @var ClientInterface|null
*/
private $client;
/**
* @var string[] ['store_id' => 'index_name']
*/
private $indexNameByStore = [];
public function __construct(
IndexNameResolver $indexNameResolver,
ClientRepositoryInterface $clientRepository,
IndexBuilderInterface $indexBuilder,
EntityStructureBuilder $entityStructureBuilder,
FieldMappingBuilderInterface $fieldMappingBuilder,
DataMapperResolverInterface $dataMapperResolver,
SaveQueryBuilderInterface $saveQueryBuilder,
Debug $debug,
?ClientInterface $client = null
) {
$this->indexNameResolver = $indexNameResolver;
$this->clientRepository = $clientRepository;
$this->indexBuilder = $indexBuilder;
$this->entityStructureBuilder = $entityStructureBuilder;
$this->fieldMappingBuilder = $fieldMappingBuilder;
$this->dataMapperResolver = $dataMapperResolver;
$this->saveQueryBuilder = $saveQueryBuilder;
$this->debug = $debug;
$this->client = $client;
}
public function prepareDocuments(array $documentData, int $storeId, string $indexerId): array
{
$documents = [];
if (!empty($documentData)) {
$documents = $this->dataMapperResolver->mapEntityData(
$documentData,
$storeId,
['indexer_id' => $indexerId]
);
}
return $documents;
}
public function saveDocuments(array $documents, int $storeId, string $indexerId): void
{
if (!empty($documents)) {
try {
$indexName = $this->indexNameResolver->getIndexName($indexerId, $storeId, $this->indexNameByStore);
if ($this->getClient()->indexExists($indexName)) {
$query = $this->saveQueryBuilder->execute($documents, $indexName);
$this->getClient()->bulkQuery($query);
}
} catch (Exception $e) {
$this->debug->debug($e);
throw $e;
}
}
}
public function deleteDocuments(array $documentIds, int $storeId, string $indexerId): void
{
try {
$indexName = $this->indexNameResolver->getIndexName($indexerId, $storeId, $this->indexNameByStore);
if (!$this->getClient()->indexExists($indexName)) {
return;
}
$query = $this->saveQueryBuilder->execute(
$documentIds,
$indexName,
SaveQueryBuilderInterface::BULK_ACTION_DELETE
);
$this->getClient()->bulkQuery($query);
} catch (Exception $e) {
$this->debug->debug($e);
throw $e;
}
}
public function cleanIndex(int $storeId, string $indexerId): void
{
// needed to fix bug with double indices in alias because of second reindex in same process
unset($this->indexNameByStore[$storeId]);
$this->checkIndex($storeId, $indexerId);
$indexName = $this->indexNameResolver->getIndexName($indexerId, $storeId, $this->indexNameByStore);
if ($this->getClient()->isEmptyIndex($indexName)) {
return;
}
$indexPattern = $this->indexNameResolver->getIndexAlias($indexerId, $storeId) . '_v';
$version = (int)(str_replace($indexPattern, '', $indexName));
$newIndexName = $indexPattern . (++$version);
if ($this->getClient()->indexExists($newIndexName)) {
$this->getClient()->deleteIndex($newIndexName);
}
$this->prepareIndex($storeId, $newIndexName, $indexerId);
}
public function checkIndex(int $storeId, string $indexerId): void
{
$indexName = $this->indexNameResolver->getIndexName($indexerId, $storeId, $this->indexNameByStore);
if (!$this->getClient()->indexExists($indexName)) {
$this->prepareIndex($storeId, $indexName, $indexerId);
}
$alias = $this->indexNameResolver->getIndexAlias($indexerId, $storeId);
if (!$this->getClient()->existsAlias($alias, $indexName)) {
$this->getClient()->updateAlias($alias, $indexName);
}
}
public function updateAlias(int $storeId, string $indexerId): void
{
if (!isset($this->indexNameByStore[$storeId])) {
return;
}
$alias = $this->indexNameResolver->getIndexAlias($indexerId, $storeId);
$oldIndex = $this->indexNameResolver->getIndexNameByAlias($alias, $storeId, $this->indexNameByStore);
if (!empty($oldIndex)) {
$params['body']['actions'][] = ['remove' => ['alias' => $alias, 'index' => $oldIndex]];
}
$params['body']['actions'][] = ['add' => ['alias' => $alias, 'index' => $this->indexNameByStore[$storeId]]];
$this->getClient()->updateAliases($params);
if ($oldIndex) {
$this->getClient()->deleteIndex($oldIndex);
}
}
public function ping(): bool
{
return $this->getClient()->ping();
}
private function prepareIndex(int $storeId, string $indexName, string $indexerId): void
{
$this->indexBuilder->setStoreId($storeId);
$this->getClient()->createIndex($indexName, $this->indexBuilder->build());
$mappingData = $this->fieldMappingBuilder->execute(
$indexName,
$storeId,
$this->entityStructureBuilder->build($indexerId)
);
$this->getClient()->putMapping($mappingData);
$this->indexNameByStore[$storeId] = $indexName;
}
private function getClient(): ClientInterface
{
if ($this->client === null) {
$this->client = $this->clientRepository->get();
}
return $this->client;
}
}