Problem/Motivation

Having set up an index with lots of content, any minor update to the search index configuration deletes the whole index. I would expect the content in the index to be marked to be reindexed at most. Deleting everything would need a manual index trigger and also a downtime in search while the content is not fully indexed.

Steps to reproduce

- Create an index
- Index content
- Export the search index, make a minor change like changing a label etc
- Import the search index and all your indexed content will be cleared

Proposed resolution

Mark the content for reindexing but not delete/clear it completely.

Remaining tasks

Check and create a patch.

User interface changes

-

API changes

-

Data model changes

-

CommentFileSizeAuthor
#6 3285438-5.patch573 bytesbkildow
#2 3285438-2.patch506 bytesvarshith
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

varshith created an issue. See original summary.

varshith’s picture

Status: Active » Needs review
StatusFileSize
new506 bytes

The following patch marks the content to be reindexed with there is any change in search index that is imported.

acbramley’s picture

Status: Needs review » Needs work

The clear() is needed when settings change, otherwise we'll get an error when updating schema for example.

Maybe we need a way to detect if settings have changed, and either clear or reindex based on that?

achap’s picture

+1 for this. I'm in the same boat with a lot of content that takes a long time to index.

Just looking at how other backends handle this and search_api_solr seems to detect if settings have changed, but calls reindex rather than clear:

https://git.drupalcode.org/project/search_api_solr/-/blob/4.x/src/Plugin/search_api/backend/SearchApiSolrBackend.php#L1060

search_api_sajari seems to not do either and just updates the schema:

https://git.drupalcode.org/project/search_api_sajari/-/blob/1.0.x/src/Plugin/search_api/backend/SearchApiSajariBackend.php#L393

@acbramley When you are referring to schema errors are you talking about a mismatch between the data structure in opensearch and drupal until re-indexing has occured?

If a clear is necessary is it possible to handle this so that downtime of search while the index is rebuilt is eliminated?

bkildow’s picture

I'm hitting a similar issue when updating the index with new fields. It looks like`clear()` gets called and further down the stack there is a search_api.task.updateIndex event that fires, and ends up calling `clear()` again and this ends up in an infinite loop. The stack looks like this:

ContainerAwareEventDispatcher.php:110, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:414, Drupal\search_api\Entity\Server->deleteAllIndexItems()
Index.php:1151, Drupal\search_api\Entity\Index->clear()
BackendClient.php:221, Drupal\search_api_opensearch\SearchAPI\BackendClient->updateIndex()
OpenSearchBackend.php:406, Drupal\search_api_opensearch\Plugin\search_api\backend\OpenSearchBackend->updateIndex()
ServerTaskManager.php:154, Drupal\search_api\Task\ServerTaskManager->executeTask()
ServerTaskManager.php:114, Drupal\search_api\Task\ServerTaskManager->processEvent()
ContainerAwareEventDispatcher.php:142, call_user_func:{/var/www/docroot/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:142}()
ContainerAwareEventDispatcher.php:142, Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
TaskManager.php:215, Drupal\search_api\Task\TaskManager->executeSpecificTask()
TaskManager.php:267, Drupal\search_api\Task\TaskManager->executeAllTasks()
ServerTaskManager.php:94, Drupal\search_api\Task\ServerTaskManager->execute()
Server.php:293, Drupal\search_api\Entity\Server->updateIndex()
Index.php:1466, Drupal\search_api\Entity\Index->reactToServerSwitch()
Index.php:1390, Drupal\search_api\Entity\Index->postSave()
SearchApiConfigEntityStorage.php:51, Drupal\search_api\Entity\SearchApiConfigEntityStorage->doPostSave()
EntityStorageBase.php:523, Drupal\Core\Entity\EntityStorageBase->save()
ConfigEntityStorage.php:253, Drupal\Core\Config\Entity\ConfigEntityStorage->save()
EntityBase.php:339, Drupal\Core\Entity\EntityBase->save()
ConfigEntityBase.php:607, Drupal\Core\Config\Entity\ConfigEntityBase->save()
UnsavedIndexConfiguration.php:179, Drupal\search_api\UnsavedIndexConfiguration->savePermanent()
IndexFieldsForm.php:490, Drupal\search_api\Form\IndexFieldsForm->save()
FormSubmitter.php:114, call_user_func_array:{/var/www/docroot/core/lib/Drupal/Core/Form/FormSubmitter.php:114}()
FormSubmitter.php:114, Drupal\Core\Form\FormSubmitter->executeSubmitHandlers()
FormSubmitter.php:52, Drupal\Core\Form\FormSubmitter->doSubmitForm()
FormBuilder.php:592, Drupal\Core\Form\FormBuilder->processForm()
FormBuilder.php:320, Drupal\Core\Form\FormBuilder->buildForm()
FormController.php:73, Drupal\Core\Controller\FormController->getContentResult()
LayoutBuilderHtmlEntityFormController.php:39, Drupal\layout_builder\Controller\LayoutBuilderHtmlEntityFormController->getContentResult()
EarlyRenderingControllerWrapperSubscriber.php:123, call_user_func_array:{/var/www/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:123}()
EarlyRenderingControllerWrapperSubscriber.php:123, Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure:/var/www/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:121-124}()
Renderer.php:564, Drupal\Core\Render\Renderer->executeInRenderContext()
EarlyRenderingControllerWrapperSubscriber.php:124, Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext()
EarlyRenderingControllerWrapperSubscriber.php:97, Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure:/var/www/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:96-98}()
HttpKernel.php:169, Symfony\Component\HttpKernel\HttpKernel->handleRaw()
HttpKernel.php:81, Symfony\Component\HttpKernel\HttpKernel->handle()
Session.php:58, Drupal\Core\StackMiddleware\Session->handle()
KernelPreHandle.php:48, Drupal\Core\StackMiddleware\KernelPreHandle->handle()
PageCache.php:106, Drupal\page_cache\StackMiddleware\PageCache->pass()
PageCache.php:85, Drupal\page_cache\StackMiddleware\PageCache->handle()
ReverseProxyMiddleware.php:48, Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
NegotiationMiddleware.php:51, Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
StackedHttpKernel.php:23, Stack\StackedHttpKernel->handle()
DrupalKernel.php:709, Drupal\Core\DrupalKernel->handle()
index.php:19, {main}()
bkildow’s picture

StatusFileSize
new573 bytes

I was able to get around the infinite loop by removing the index and adding it back, instead of calling clear().

kim.pepper’s picture

Just coming back to this, we can't change or remove field mappings on existing indexes, we can only add additional field mappings.

longwave’s picture

Also running into this, even just a minor change to an index config that could simply be reindexed over the existing content means the index is cleared during deployment.

Index::postSave() already has some logic to handle this problem, can we just rely on this? Or at least detect the situation where fields are changed/removed and only clear in that case?

        // React on possible changes that would require re-indexing, etc.
        $this->reactToServerSwitch($original);
        $this->reactToDatasourceSwitch($original);
        $this->reactToTrackerSwitch($original);
        $this->reactToProcessorChanges($original);
longwave’s picture

A method we have tried to use to work around this is blue/green deployments; we have two identical indexes, and when we need to make a change we write to index 2 and ensure it is fully indexed before switching reads to use index 2, and then swap over again next time around. This adds manual deployment steps and is prone to error, though; it would be nice if this could be supported natively but not sure if this would be better off in Search API itself or in here.

robphillips made their first commit to this issue’s fork.

bobooon’s picture

Status: Needs work » Needs review

Took a crack at the problem. Search API Solr offers up a similar solution. Re-index is only triggered when a indexed field has changed. Tested with both in-site configuration changes and using configuration sync. There might be some edge cases. Definitely needs more eyes on it.

https://git.drupalcode.org/project/search_api_solr/-/blob/4.x/src/Plugin...

Status: Needs review » Needs work

The last submitted patch, 6: 3285438-5.patch, failed testing. View results

kim.pepper’s picture

Hiding the patch because we are using MRs and Gitlab CI now.

achap’s picture

Thanks for the MR. Checking if fields have changed does seem like a good idea but I think a clear rather than a re-index will be necessary as alluded to in previous comments. From the Opensearch docs:

If you want to create or add mappings and fields to an index, you can use the put mapping API operation. For an existing mapping, this operation updates the mapping.

You can’t use this operation to update mappings that already map to existing data in the index. You must first create a new index with your desired mappings, and then use the reindex API operation to map all the documents from your old index to the new index. If you don’t want any downtime while you re-index your indexes, you can use aliases.

See docs: https://opensearch.org/docs/latest/api-reference/index-apis/put-mapping/

So if we could detect if a field doesn't yet exist then we could use the re-index flag, and if it does already exist then we would need to clear. However that could get complicated if one field is added and another changed etc.

So just checking if any fields exist in new index vs original and only clearing then already seems like an improvement. However I think the clear would need to come before the call to updateSettings and updateFieldMapping

achap’s picture

Version: 1.x-dev » 2.x-dev
Status: Needs work » Needs review

I took a stab at this with MR#52

It retrieves the mappings from the OpenSearch server and compares them with the local Drupal mappings after event subscribers have fired.

I don't think comparing the original index fields to the new ones will work because the modified mappings after event subscribers have fired aren't stored anywhere and so it's not really possible to compare.

The other thing to be aware of is the dynamic mappings in OpenSearch. If you don't explicitly provide a type it will guess based off the data that is indexed. That means that every time you click save even if nothing has changed it will clear the index (because there are no local mappings). This is mostly a problem if you create fields in processors etc and the fix is just to use the IndexParamsEvent to explicitly give your custom fields the correct types. I have found that if you incorrectly give a Drupal field that is a float for example a string type in Search API then OS will override it with the float type in the mappings once data has been indexed. That will also cause clearing rather than re-indexing. So you need to be careful to assign the correct type.

Did not tackle settings (analysers etc), only field mappings and doesn't negate the need for a blue/green deployment but should definitely help reduce the amount of times you need to switch indexes.

kim.pepper’s picture

This MR will need to be rebased to go onto 3.x branch. It's currently on 1.x which is security fixes only.

achap’s picture

Version: 2.x-dev » 3.x-dev
kim.pepper’s picture

Status: Needs review » Needs work

NW for feedback and test fails

achap’s picture

Status: Needs work » Needs review

Have updated the code based on feedback. Looks like that error was unrelated to my code but I was able to trace it to the search_api_item table not being installed in the SpellCheckTest so I added there.

kim.pepper’s picture

Status: Needs review » Reviewed & tested by the community

This looks good to me. I'll leave it as RTBC in case anyone else has feedback over the next 24hrs.

achap’s picture

Status: Reviewed & tested by the community » Needs review

Setting back to needs review as I found a small edge case after the type hinting changes when the OS mappings are not set.

  • kim.pepper committed e9c0b841 on 3.x authored by achap
    Issue #3285438 by achap, varshith, bkildow, kim.pepper, longwave,...

kim.pepper’s picture

Status: Needs review » Fixed

Committed to 3.x. Thanks!

  • kim.pepper committed 1e35a267 on 2.x
    Issue #3285438 by achap, varshith, bkildow, kim.pepper, longwave,...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.