mirror of
https://github.com/Codappix/search_core.git
synced 2024-12-23 12:16:09 +01:00
TASK: Finish deletion of index and documents feature
We replace the "flush" and "delete" by "delete" and "deletedocuments" logic. This makes it more obvious what will happen, without reading the docs. Also we kept the logic to always provide the index name, as we will need them in the future. Due to elasticsearch v6 changes no types are allowed in the same index in the future. Therefore we need to make it possible to use different indexes in the future, leading to the need to provide the document type all the time.
This commit is contained in:
parent
28a8dd1ab4
commit
689f293194
15 changed files with 114 additions and 96 deletions
|
@ -63,24 +63,24 @@ class IndexCommandController extends CommandController
|
|||
*
|
||||
* @param string $identifier Comma separated list of identifiers.
|
||||
*/
|
||||
public function deleteCommand(string $identifiers)
|
||||
public function deleteDocumentsCommand(string $identifiers)
|
||||
{
|
||||
$this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) {
|
||||
$indexer->deleteDocuments();
|
||||
$indexer->deleteAllDocuments();
|
||||
$this->outputLine('Documents in index ' . $indexer->getIdentifier() . ' were deleted.');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Will flush the index for given identifiers from backend.
|
||||
* Will delete the index for given identifiers.
|
||||
*
|
||||
* @param string $identifier Comma separated list of identifiers.
|
||||
*/
|
||||
public function flushCommand(string $identifiers = 'pages')
|
||||
public function deleteCommand(string $identifiers = 'pages')
|
||||
{
|
||||
$this->executeForIdentifier($identifiers, function (IndexerInterface $indexer) {
|
||||
$indexer->delete();
|
||||
$this->outputLine('Indice ' . $indexer->getIdentifier() . ' was flushed.');
|
||||
$this->outputLine('Index ' . $indexer->getIdentifier() . ' was deleted.');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -51,17 +51,17 @@ interface ConnectionInterface
|
|||
public function deleteDocument(string $documentType, string $identifier);
|
||||
|
||||
/**
|
||||
* Search by given request and return result.
|
||||
* Will all documents of certain kind / in certain index.
|
||||
*/
|
||||
public function search(SearchRequestInterface $searchRequest): SearchResultInterface;
|
||||
|
||||
/**
|
||||
* Will delete the index / db of defined document type.
|
||||
*/
|
||||
public function deleteIndexByDocumentType(string $documentType);
|
||||
public function deleteAllDocuments(string $documentType);
|
||||
|
||||
/**
|
||||
* Will delete the whole index / db.
|
||||
*/
|
||||
public function deleteIndex();
|
||||
public function deleteIndex(string $documentType);
|
||||
|
||||
/**
|
||||
* Search by given request and return result.
|
||||
*/
|
||||
public function search(SearchRequestInterface $searchRequest): SearchResultInterface;
|
||||
}
|
||||
|
|
|
@ -142,6 +142,29 @@ class Elasticsearch implements Singleton, ConnectionInterface
|
|||
}
|
||||
}
|
||||
|
||||
public function deleteAllDocuments(string $documentType)
|
||||
{
|
||||
$this->deleteDocumentsByQuery($documentType, Query::create([
|
||||
'query' => [
|
||||
'term' => [
|
||||
'search_document_type' => $documentType,
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public function deleteIndex(string $documentType)
|
||||
{
|
||||
try {
|
||||
$this->indexFactory->getIndex($this->connection, $documentType)->delete();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->notice(
|
||||
'Index did not exist, therefore was not deleted.',
|
||||
[$documentType, $e]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateDocument(string $documentType, array $document)
|
||||
{
|
||||
$this->withType(
|
||||
|
@ -162,49 +185,6 @@ class Elasticsearch implements Singleton, ConnectionInterface
|
|||
);
|
||||
}
|
||||
|
||||
public function deleteIndex()
|
||||
{
|
||||
$index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName());
|
||||
|
||||
if (!$index->exists()) {
|
||||
$this->logger->notice(
|
||||
'Index did not exist, therefore was not deleted.',
|
||||
[$this->indexFactory->getIndexName()]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$index->delete();
|
||||
}
|
||||
|
||||
public function deleteIndexByDocumentType(string $documentType)
|
||||
{
|
||||
$this->deleteIndexByQuery(Query::create([
|
||||
'query' => [
|
||||
'term' => [
|
||||
'search_document_type' => $documentType,
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
private function deleteIndexByQuery(Query $query)
|
||||
{
|
||||
$index = $this->connection->getClient()->getIndex($this->indexFactory->getIndexName());
|
||||
if (!$index->exists()) {
|
||||
$this->logger->notice(
|
||||
'Index did not exist, therefore items can not be deleted by query.',
|
||||
[$this->indexFactory->getIndexName(), $query->getQuery()]
|
||||
);
|
||||
return;
|
||||
}
|
||||
$response = $index->deleteByQuery($query);
|
||||
if ($response->getData()['deleted'] > 0) {
|
||||
// Refresh index when delete query is invoked
|
||||
$index->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public function search(SearchRequestInterface $searchRequest): SearchResultInterface
|
||||
{
|
||||
$this->logger->debug('Search for', [$searchRequest->getSearchTerm()]);
|
||||
|
@ -232,4 +212,22 @@ class Elasticsearch implements Singleton, ConnectionInterface
|
|||
$callback($type, $documentType);
|
||||
$type->getIndex()->refresh();
|
||||
}
|
||||
|
||||
private function deleteDocumentsByQuery(string $documentType, Query $query)
|
||||
{
|
||||
try {
|
||||
$index = $this->indexFactory->getIndex($this->connection, $documentType);
|
||||
$response = $index->deleteByQuery($query);
|
||||
|
||||
if ($response->getData()['deleted'] > 0) {
|
||||
// Refresh index when delete query is invoked
|
||||
$index->refresh();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->notice(
|
||||
'Index did not exist, therefore items can not be deleted by query.',
|
||||
[$documentType, $query->getQuery()]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,22 +70,35 @@ class IndexFactory implements Singleton
|
|||
}
|
||||
|
||||
/**
|
||||
* Get an index based on TYPO3 table name.
|
||||
* @throws \InvalidArgumentException If index does not exist.
|
||||
*/
|
||||
public function getIndex(Connection $connection, string $documentType): \Elastica\Index
|
||||
{
|
||||
$index = $connection->getClient()->getIndex($this->getIndexName());
|
||||
|
||||
if ($index->exists() === false) {
|
||||
$config = $this->getConfigurationFor($documentType);
|
||||
$this->logger->debug(sprintf('Create index %s.', $documentType), [$documentType, $config]);
|
||||
$index->create($config);
|
||||
$this->logger->debug(sprintf('Created index %s.', $documentType), [$documentType]);
|
||||
throw new \InvalidArgumentException('The requested index does not exist.', 1546173102);
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
public function createIndex(Connection $connection, string $documentType): \Elastica\Index
|
||||
{
|
||||
$index = $connection->getClient()->getIndex($this->getIndexName());
|
||||
|
||||
if ($index->exists() === true) {
|
||||
return $index;
|
||||
}
|
||||
|
||||
$config = $this->getConfigurationFor($documentType);
|
||||
$this->logger->debug(sprintf('Create index %s.', $documentType), [$documentType, $config]);
|
||||
$index->create($config);
|
||||
$this->logger->debug(sprintf('Created index %s.', $documentType), [$documentType]);
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
protected function getConfigurationFor(string $documentType): array
|
||||
{
|
||||
try {
|
||||
|
|
|
@ -49,12 +49,9 @@ class TypeFactory implements Singleton
|
|||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an index bases on TYPO3 table name.
|
||||
*/
|
||||
public function getType(string $documentType): \Elastica\Type
|
||||
{
|
||||
$index = $this->indexFactory->getIndex($this->connection, $documentType);
|
||||
$index = $this->indexFactory->createIndex($this->connection, $documentType);
|
||||
return $index->getType('document');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,14 +106,14 @@ abstract class AbstractIndexer implements IndexerInterface
|
|||
public function delete()
|
||||
{
|
||||
$this->logger->info('Start deletion of index.');
|
||||
$this->connection->deleteIndex();
|
||||
$this->connection->deleteIndex($this->getDocumentName());
|
||||
$this->logger->info('Finish deletion.');
|
||||
}
|
||||
|
||||
public function deleteDocuments()
|
||||
public function deleteAllDocuments()
|
||||
{
|
||||
$this->logger->info('Start deletion of indexed documents.');
|
||||
$this->connection->deleteIndexByDocumentType($this->getDocumentName());
|
||||
$this->connection->deleteAllDocuments($this->getDocumentName());
|
||||
$this->logger->info('Finish deletion.');
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,9 @@ interface IndexerInterface
|
|||
public function delete();
|
||||
|
||||
/**
|
||||
* Delete the whole index.
|
||||
* Delete all documents from index.
|
||||
*/
|
||||
public function deleteDocuments();
|
||||
public function deleteAllDocuments();
|
||||
|
||||
/**
|
||||
* Receives the identifier of the indexer itself.
|
||||
|
|
|
@ -8,7 +8,7 @@ v0.1.0
|
|||
0.1.0/2018-changed-interfaces
|
||||
0.1.0/2018-elasticsearch-upgrade
|
||||
0.1.0/2018-search-service-interface
|
||||
0.1.0/20181027-added-flush-command
|
||||
0.1.0/20181027-added-delete-all-documents-command
|
||||
0.1.0/20181027-allow-multiple-identifier-on-cli
|
||||
0.1.0/20181027-remove-cms7-support
|
||||
0.1.0/20181028-fluid-templating-list-items
|
||||
|
|
|
@ -5,7 +5,7 @@ Some interfaces and abstract classes have been adjusted:
|
|||
|
||||
``Codappix\SearchCore\Connection\ConnectionInterface``:
|
||||
|
||||
* New method ``public function deleteIndexByDocumentType(string $documentType);``
|
||||
* New method ``public function deleteAllDocuments(string $documentType);``
|
||||
|
||||
``Codappix\SearchCore\Domain\Index\IndexerInterface``:
|
||||
|
||||
|
@ -28,4 +28,12 @@ Also some exceptions have changed:
|
|||
throws an ``\InvalidArgumentException`` instead of ``\Exception``, if no
|
||||
``search_identifier`` was provided.
|
||||
|
||||
* ``Codappix\SearchCore\Connection\Elasticsearch\IndexFactory::getIndex()`` now
|
||||
throws an ``\InvalidArgumentException`` if the index does not exist. Leaving
|
||||
handling up to the caller.
|
||||
|
||||
Before the index was created if it didn't exist. To create an index, a new method
|
||||
``public function createIndex(Connection $connection, string $documentType): \Elastica\Index``
|
||||
was added. This method will only create the index if it didn't exist before.
|
||||
In the end, the index is returned always. Making this method a 1:1 replacement for
|
||||
older ``getIndex()``.
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
Feature "Added delete documents command"
|
||||
========================================
|
||||
|
||||
A new command to delete all documents within an index was added. In contrast to the
|
||||
existing delete command, this deletes only documents but keeps the index.
|
||||
|
||||
E.g. if your backend is Elasticsearch or a relational database, the index or table is
|
||||
kept, including structure or mappings, while only the documents or rows are removed.
|
||||
|
||||
In contrast the existing delete command will still remove the index or table itself,
|
||||
depending on the used connection.
|
|
@ -1,6 +0,0 @@
|
|||
Feature "Added flush command"
|
||||
=============================
|
||||
|
||||
A new command to flush indices was added. In contrast to the existing delete command,
|
||||
this one will delete the whole index, while the existing delete command only deletes
|
||||
all documents within an index.
|
|
@ -36,18 +36,17 @@ documents from the index.
|
|||
Multiple indexes can be called by providing a comma separated list of identifiers as
|
||||
a single argument. Spaces before and after commas are ignored.
|
||||
|
||||
.. _usage_manual_flush:
|
||||
.. _usage_manual_delete_all_documents:
|
||||
|
||||
Manual flush
|
||||
------------
|
||||
Manual delete all documents
|
||||
---------------------------
|
||||
|
||||
You can trigger flush for indexes from CLI::
|
||||
You can trigger deletion of all documents for indexes from CLI::
|
||||
|
||||
./typo3/cli_dispatch.phpsh extbase index:flush --identifiers 'pages'
|
||||
./bin/typo3cms index:flush --identifiers 'pages'
|
||||
./typo3/cli_dispatch.phpsh extbase index:deletedocuments --identifiers 'pages'
|
||||
./bin/typo3cms index:deletedocuments --identifiers 'pages'
|
||||
|
||||
This will flush the index for the table ``pages``. Flush means removing the index
|
||||
from backend.
|
||||
This will delete all documents within the index for the table ``pages``.
|
||||
|
||||
Multiple indexes can be called by providing a comma separated list of identifiers as
|
||||
a single argument. Spaces before and after commas are ignored.
|
||||
|
|
|
@ -89,14 +89,12 @@ class IndexDeletionTest extends AbstractFunctionalTestCase
|
|||
$response = $this->client->request('typo3content/_search?q=*:*');
|
||||
$this->assertSame($response->getData()['hits']['total'], 5, 'Not exactly 5 documents are in index.');
|
||||
|
||||
$contentIndexer->deleteDocuments();
|
||||
$contentIndexer->deleteAllDocuments();
|
||||
$response = $this->client->request('typo3content/_search?q=*:*');
|
||||
$this->assertSame($response->getData()['hits']['total'], 2, 'Not exactly 2 documents are in index.');
|
||||
|
||||
$pageIndexer->deleteDocuments();
|
||||
$pageIndexer->deleteAllDocuments();
|
||||
$response = $this->client->request('typo3content/_search?q=*:*');
|
||||
$this->assertSame($response->getData()['hits']['total'], 0, 'Index should be empty.');
|
||||
|
||||
$index->delete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ class IndexCommandControllerTest extends AbstractUnitTestCase
|
|||
/**
|
||||
* @test
|
||||
*/
|
||||
public function deletionIsPossible()
|
||||
public function deletionOfDocumentsIsPossible()
|
||||
{
|
||||
$indexerMock = $this->getMockBuilder(TcaIndexer::class)
|
||||
->disableOriginalConstructor()
|
||||
|
@ -114,14 +114,14 @@ class IndexCommandControllerTest extends AbstractUnitTestCase
|
|||
->will($this->returnValue($indexerMock));
|
||||
|
||||
$indexerMock->expects($this->once())
|
||||
->method('deleteDocuments');
|
||||
$this->subject->deleteCommand('allowedTable');
|
||||
->method('deleteAllDocuments');
|
||||
$this->subject->deleteDocumentsCommand('allowedTable');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function flushIsPossible()
|
||||
public function deletionOfIndexIsPossible()
|
||||
{
|
||||
$indexerMock = $this->getMockBuilder(TcaIndexer::class)
|
||||
->disableOriginalConstructor()
|
||||
|
@ -139,7 +139,7 @@ class IndexCommandControllerTest extends AbstractUnitTestCase
|
|||
|
||||
$indexerMock->expects($this->once())
|
||||
->method('delete');
|
||||
$this->subject->flushCommand('pages');
|
||||
$this->subject->deleteCommand('pages');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -150,6 +150,6 @@ class IndexFactoryTest extends AbstractUnitTestCase
|
|||
])
|
||||
);
|
||||
|
||||
$this->subject->getIndex($connection, 'someIndex');
|
||||
$this->subject->createIndex($connection, 'someIndex');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue