Skip to content

Commit

Permalink
feat(reindex): Extend instance-records reindex endpoint with passing …
Browse files Browse the repository at this point in the history
…index settings

- Extend full/upload reindex endpoints with index settings
- Recreate indices on publishing merge ranges instead of doing this on upload start in order to use index settings
- Add instance reindexing to tenant service
- Remove instance record type from old reindex endpoint

Implements: MSEARCH-853
  • Loading branch information
viacheslavkol committed Oct 16, 2024
1 parent 3e4848d commit 0412a43
Show file tree
Hide file tree
Showing 16 changed files with 142 additions and 102 deletions.
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Endpoint `GET /search/consortium/batch/holdings` requires `consortium-search.holdings.batch.collection.get` permission

### New APIs versions
* Provides `indices v0.8`
* Provides `indices v1.0`
* Provides `search v1.3`
* Provides `consortium-search v2.0`
* Provides `browse v1.4`
Expand Down Expand Up @@ -46,6 +46,7 @@
* Support filters for subject source and type on subject browse ([MSEARCH-805](https://folio-org.atlassian.net/browse/MSEARCH-805))
* Implement new re-index flow for instance records ([MSEARCH-793](https://folio-org.atlassian.net/issues/MSEARCH-793), [MSEARCH-794](https://folio-org.atlassian.net/issues/MSEARCH-794), [MSEARCH-796](https://folio-org.atlassian.net/issues/MSEARCH-796), [MSEARCH-797](https://folio-org.atlassian.net/issues/MSEARCH-797), [MSEARCH-798](https://folio-org.atlassian.net/issues/MSEARCH-798), [MSEARCH-799](https://folio-org.atlassian.net/issues/MSEARCH-799), [MSEARCH-800](https://folio-org.atlassian.net/issues/MSEARCH-800), [MSEARCH-801](https://folio-org.atlassian.net/issues/MSEARCH-801), [MSEARCH-802](https://folio-org.atlassian.net/issues/MSEARCH-802))
* Implement Linked Data HUB index and search API ([MSEARCH-844](https://folio-org.atlassian.net/browse/MSEARCH-844))
* Extend instance-records reindex endpoint with index settings ([MSEARCH-853](https://folio-org.atlassian.net/browse/MSEARCH-853))

### Bug fixes
* Do not delete kafka topics if collection topic is enabled ([MSEARCH-725](https://folio-org.atlassian.net/browse/MSEARCH-725))
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,13 @@ x-okapi-token: [JWT_TOKEN]
{
"recreateIndex": true,
"resourceName": "instance"
"resourceName": "authority"
}
```

* `resourceName` parameter is optional and equal to `instance` by default. Possible values: `instance`, `authority`, `location`,
* `resourceName` parameter is optional and equal to `authority` by default. Possible values: `authority`, `location`,
`linked-data-instance`, `linked-data-work`, `linked-data-hub`. Please note that `location` reindex is synchronous.
Refer to [Indexing of Instance Records](#indexing-of-instance-records) section for reindexing of instances
* `recreateIndex` parameter is optional and equal to `false` by default. If it is equal to `true` then mod-search
will drop existing indices for tenant and resource, creating them again. Executing request with this parameter
equal to `true` in query will erase all the tenant data in mod-search.
Expand All @@ -341,13 +342,13 @@ There is no end-to-end monitoring implemented yet, however it is possible to mon
how many records published to Kafka topic use inventory API:

```http
GET [OKAPI_URL]/instance-storage/reindex/[reindex job id]
GET [OKAPI_URL]/authority-storage/reindex/[reindex job id]
```

_reindex job id_ - id returned by `/search/index/inventory/reindex` endpoint.

In order to estimate total records that actually added to the index, you can send a "match all" search query and check
`totalRecords`, e.g. `GET /search/instances?query=id="*"`. Alternatively you can query Elasticsearch directly,
`totalRecords`, e.g. `GET /search/authorities?query=id="*"`. Alternatively you can query Elasticsearch directly,
see [ES search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html#query-dsl-match-all-query).

## Indexing of Instance Records
Expand Down
2 changes: 1 addition & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"provides": [
{
"id": "indices",
"version": "0.8",
"version": "1.0",
"handlers": [
{
"methods": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.folio.search.domain.dto.CreateIndexRequest;
import org.folio.search.domain.dto.FolioCreateIndexResponse;
import org.folio.search.domain.dto.FolioIndexOperationResponse;
import org.folio.search.domain.dto.IndexSettings;
import org.folio.search.domain.dto.ReindexJob;
import org.folio.search.domain.dto.ReindexRequest;
import org.folio.search.domain.dto.ReindexStatusItem;
Expand Down Expand Up @@ -50,15 +51,15 @@ public ResponseEntity<FolioIndexOperationResponse> indexRecords(List<ResourceEve
}

@Override
public ResponseEntity<Void> reindexInstanceRecords(String tenantId) {
public ResponseEntity<Void> reindexInstanceRecords(String tenantId, IndexSettings indexSettings) {
log.info("Attempting to run full-reindex for instance records [tenant: {}]", tenantId);
reindexService.submitFullReindex(tenantId);
reindexService.submitFullReindex(tenantId, indexSettings);
return ResponseEntity.ok().build();
}

@Override
public ResponseEntity<Void> reindexUploadInstanceRecords(String tenantId, ReindexUploadDto reindexUploadDto) {
reindexService.submitUploadReindex(tenantId, reindexUploadDto.getEntityTypes());
reindexService.submitUploadReindex(tenantId, reindexUploadDto);
return ResponseEntity.ok().build();
}

Expand Down
13 changes: 11 additions & 2 deletions src/main/java/org/folio/search/service/SearchTenantService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import org.folio.search.configuration.properties.SearchConfigurationProperties;
import org.folio.search.domain.dto.LanguageConfig;
import org.folio.search.domain.dto.ReindexRequest;
import org.folio.search.model.types.ReindexEntityType;
import org.folio.search.service.browse.CallNumberBrowseRangeService;
import org.folio.search.service.consortium.LanguageConfigServiceDecorator;
import org.folio.search.service.metadata.ResourceDescriptionService;
import org.folio.search.service.reindex.ReindexService;
import org.folio.spring.FolioExecutionContext;
import org.folio.spring.liquibase.FolioSpringLiquibase;
import org.folio.spring.service.PrepareSystemUserService;
Expand All @@ -32,6 +34,7 @@ public class SearchTenantService extends TenantService {
private static final String CENTRAL_TENANT_ID_PARAM_NAME = "centralTenantId";

private final IndexService indexService;
private final ReindexService reindexService;
private final KafkaAdminService kafkaAdminService;
private final PrepareSystemUserService prepareSystemUserService;
private final LanguageConfigServiceDecorator languageConfigService;
Expand All @@ -41,7 +44,7 @@ public class SearchTenantService extends TenantService {

public SearchTenantService(JdbcTemplate jdbcTemplate, FolioExecutionContext context,
FolioSpringLiquibase folioSpringLiquibase, KafkaAdminService kafkaAdminService,
IndexService indexService,
IndexService indexService, ReindexService reindexService,
PrepareSystemUserService prepareSystemUserService,
LanguageConfigServiceDecorator languageConfigService,
CallNumberBrowseRangeService callNumberBrowseRangeService,
Expand All @@ -50,6 +53,7 @@ public SearchTenantService(JdbcTemplate jdbcTemplate, FolioExecutionContext cont
super(jdbcTemplate, context, folioSpringLiquibase);
this.kafkaAdminService = kafkaAdminService;
this.indexService = indexService;
this.reindexService = reindexService;
this.prepareSystemUserService = prepareSystemUserService;
this.languageConfigService = languageConfigService;
this.callNumberBrowseRangeService = callNumberBrowseRangeService;
Expand Down Expand Up @@ -167,7 +171,12 @@ private void createIndexesAndReindex(TenantAttributes tenantAttributes) {
.filter(parameter -> parameter.getKey().equals(REINDEX_PARAM_NAME) && parseBoolean(parameter.getValue()))
.findFirst()
.ifPresent(parameter -> resourceNames.forEach(resource -> {
if (resourceDescriptionService.get(resource).isReindexSupported()) {
if (!resourceDescriptionService.get(resource).isReindexSupported()) {
return;
}
if (resource.getName().equals(ReindexEntityType.INSTANCE.getType())) {
reindexService.submitFullReindex(context.getTenantId(), null);
} else {
indexService.reindexInventory(context.getTenantId(),
new ReindexRequest().resourceName(ReindexRequest.ResourceNameEnum.fromValue(resource.getName())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.log4j.Log4j2;
import org.folio.search.domain.dto.IndexSettings;
import org.folio.search.model.types.ReindexEntityType;
import org.folio.search.service.IndexService;
import org.folio.search.service.reindex.jdbc.ReindexJdbcRepository;
Expand All @@ -33,11 +34,11 @@ public void deleteAllRecords() {
}
}

public void recreateIndex(ReindexEntityType reindexEntityType, String tenantId) {
public void recreateIndex(ReindexEntityType reindexEntityType, String tenantId, IndexSettings indexSettings) {
try {
var resourceType = RESOURCE_NAME_MAP.get(reindexEntityType);
indexService.dropIndex(resourceType, tenantId);
indexService.createIndex(resourceType, tenantId);
indexService.createIndex(resourceType, tenantId, indexSettings);
} catch (Exception e) {
log.warn("Index cannot be recreated for resource={}, message={}", reindexEntityType, e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package org.folio.search.service.reindex;

import java.util.Arrays;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.message.FormattedMessage;
import org.folio.search.domain.dto.FolioIndexOperationResponse;
import org.folio.search.domain.dto.ReindexUploadDto;
import org.folio.search.exception.ReindexException;
import org.folio.search.model.event.ReindexRangeIndexEvent;
import org.folio.search.model.event.ReindexRecordsEvent;
import org.folio.search.model.types.ReindexEntityType;
import org.folio.search.repository.PrimaryResourceRepository;
import org.folio.search.service.converter.MultiTenantSearchDocumentConverter;
import org.folio.spring.FolioExecutionContext;
Expand Down Expand Up @@ -64,8 +63,7 @@ public boolean process(ReindexRecordsEvent event) {
event.getRangeId(), event.getRecordType());
mergeRangeService.updateFinishDate(entityType, event.getRangeId());
if (reindexStatusService.isMergeCompleted()) {
reindexService.submitUploadReindex(context.getTenantId(),
Arrays.asList(ReindexUploadDto.EntityTypesEnum.values()));
reindexService.submitUploadReindex(context.getTenantId(), ReindexEntityType.supportUploadTypes());
}
}

Expand Down
38 changes: 30 additions & 8 deletions src/main/java/org/folio/search/service/reindex/ReindexService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.folio.search.converter.ReindexEntityTypeMapper;
import org.folio.search.domain.dto.IndexSettings;
import org.folio.search.domain.dto.ReindexUploadDto;
import org.folio.search.exception.RequestValidationException;
import org.folio.search.integration.folio.InventoryService;
Expand Down Expand Up @@ -62,7 +63,7 @@ public ReindexService(ConsortiumTenantService consortiumService,
this.reindexCommonService = reindexCommonService;
}

public CompletableFuture<Void> submitFullReindex(String tenantId) {
public CompletableFuture<Void> submitFullReindex(String tenantId, IndexSettings indexSettings) {
log.info("submitFullReindex:: for [tenantId: {}]", tenantId);

validateTenant(tenantId);
Expand All @@ -81,6 +82,7 @@ public CompletableFuture<Void> submitFullReindex(String tenantId) {
mergeRangeService.saveMergeRanges(rangesForAllTenants);
}, reindexFullExecutor)
.thenRun(() -> publishRecordsRange(tenantId))
.thenRun(() -> recreateIndices(tenantId, ReindexEntityType.supportUploadTypes(), indexSettings))
.handle((unused, throwable) -> {
if (throwable != null) {
log.error("initFullReindex:: process failed [tenantId: {}, error: {}]", tenantId, throwable);
Expand All @@ -94,20 +96,34 @@ public CompletableFuture<Void> submitFullReindex(String tenantId) {
}

public CompletableFuture<Void> submitUploadReindex(String tenantId,
List<ReindexUploadDto.EntityTypesEnum> entityTypes) {
log.info("submitUploadReindex:: for [tenantId: {}, entities: {}]", tenantId, entityTypes);
var reindexEntityTypes = entityTypeMapper.convert(entityTypes)
ReindexUploadDto reindexUploadDto) {
var entityTypes = entityTypeMapper.convert(reindexUploadDto.getEntityTypes())
.stream().filter(ReindexEntityType::isSupportsUpload).toList();
return submitUploadReindex(tenantId, entityTypes, true, reindexUploadDto.getIndexSettings());
}

public CompletableFuture<Void> submitUploadReindex(String tenantId,
List<ReindexEntityType> entityTypes) {
return submitUploadReindex(tenantId, entityTypes, false, null);
}

validateUploadReindex(tenantId, reindexEntityTypes);
private CompletableFuture<Void> submitUploadReindex(String tenantId,
List<ReindexEntityType> entityTypes,
boolean recreateIndex,
IndexSettings indexSettings) {
log.info("submitUploadReindex:: for [tenantId: {}, entities: {}]", tenantId, entityTypes);

for (var reindexEntityType : reindexEntityTypes) {
validateUploadReindex(tenantId, entityTypes);

for (var reindexEntityType : entityTypes) {
statusService.recreateUploadStatusRecord(reindexEntityType);
reindexCommonService.recreateIndex(reindexEntityType, tenantId);
if (recreateIndex) {
reindexCommonService.recreateIndex(reindexEntityType, tenantId, indexSettings);
}
}

var futures = new ArrayList<>();
for (var entityType : reindexEntityTypes) {
for (var entityType : entityTypes) {
var future = CompletableFuture.runAsync(() ->
uploadRangeService.prepareAndSendIndexRanges(entityType), reindexUploadExecutor)
.handle((unused, throwable) -> {
Expand All @@ -124,6 +140,12 @@ public CompletableFuture<Void> submitUploadReindex(String tenantId,
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
}

private void recreateIndices(String tenantId, List<ReindexEntityType> entityTypes, IndexSettings indexSettings) {
for (var reindexEntityType : entityTypes) {
reindexCommonService.recreateIndex(reindexEntityType, tenantId, indexSettings);
}
}

private List<MergeRangeEntity> processForConsortium(String tenantId) {
List<MergeRangeEntity> mergeRangeEntities = new ArrayList<>();
var memberTenants = consortiumService.getConsortiumTenants(tenantId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
value:
numberOfShards: 1
numberOfReplicas: 1
refreshInterval: 1
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ post:
description: Initiates the full reindex for the inventory instance records
tags:
- index-management
requestBody:
content:
application/json:
examples:
indexSettings:
$ref: '../../examples/request/indexSettings.yaml'
schema:
$ref: '../../schemas/entity/indexSettings.yaml'
parameters:
- $ref: '../../parameters/x-okapi-tenant-header.yaml'
responses:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ properties:
resourceName:
type: string
description: Resource name to run reindex for
default: instance
default: authority
enum:
- instance
- authority
- location
- linked-data-instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ properties:
- contributor
- classification
minItems: 1
indexSettings:
description: Index settings to apply for index
$ref: '../entity/indexSettings.yaml'
required:
- entityTypes
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.concurrent.CompletableFuture;
import org.folio.search.domain.dto.CreateIndexRequest;
import org.folio.search.domain.dto.IndexDynamicSettings;
import org.folio.search.domain.dto.IndexSettings;
import org.folio.search.domain.dto.ReindexJob;
import org.folio.search.domain.dto.ReindexRequest;
import org.folio.search.domain.dto.ReindexStatusItem;
Expand Down Expand Up @@ -80,9 +81,19 @@ class IndexManagementControllerTest {

@Test
void submitReindexFull_positive() throws Exception {
when(reindexService.submitFullReindex(TENANT_ID)).thenReturn(new CompletableFuture<>());
when(reindexService.submitFullReindex(TENANT_ID, null)).thenReturn(new CompletableFuture<>());

mockMvc.perform(post(reindexFullPath()).header(XOkapiHeaders.TENANT, TENANT_ID))
mockMvc.perform(post(reindexFullPath())
.contentType(APPLICATION_JSON).header(XOkapiHeaders.TENANT, TENANT_ID))
.andExpect(status().isOk());
}

@Test
void submitReindexFull_positive_withSettings() throws Exception {
var requestBody = new IndexSettings().numberOfShards(1).refreshInterval(2).numberOfReplicas(3);
when(reindexService.submitFullReindex(TENANT_ID, requestBody)).thenReturn(new CompletableFuture<>());

mockMvc.perform(preparePostRequest(reindexFullPath(), asJsonString(requestBody)))
.andExpect(status().isOk());
}

Expand All @@ -96,6 +107,19 @@ void submitReindexUpload_positive() throws Exception {
.andExpect(status().isOk());
}

@Test
void submitReindexUpload_positive_withSettings() throws Exception {
var indexSettings = new IndexSettings().numberOfShards(1).refreshInterval(2).numberOfReplicas(3);
var requestBody = new ReindexUploadDto()
.addEntityTypesItem(ReindexUploadDto.EntityTypesEnum.INSTANCE)
.indexSettings(indexSettings);
when(reindexService.submitUploadReindex(TENANT_ID, requestBody)).thenReturn(new CompletableFuture<>());

mockMvc.perform(preparePostRequest(reindexUploadPath(), asJsonString(requestBody))
.header(XOkapiHeaders.TENANT, TENANT_ID))
.andExpect(status().isOk());
}

@Test
void createIndex_positive() throws Exception {
when(indexService.createIndex(RESOURCE, TENANT_ID))
Expand Down
13 changes: 1 addition & 12 deletions src/test/java/org/folio/search/controller/IndexManagementIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static void cleanUp() {
}

@Test
void runReindex_positive_instance() throws Exception {
void runReindex_positive_authority() throws Exception {
var request = post(ApiEndpoints.reindexPath())
.headers(defaultHeaders())
.header(XOkapiHeaders.URL, okapi.getOkapiUrl())
Expand All @@ -79,17 +79,6 @@ void runReindex_positive_instance() throws Exception {
.andExpect(jsonPath("$.submittedDate", is("2021-11-08T12:00:00.000+00:00")));
}

@Test
void runReindex_positive_authority() throws Exception {
var request = getReindexRequestBuilder(asJsonString(new ReindexRequest().resourceName(AUTHORITY)));

mockMvc.perform(request)
.andExpect(status().isOk())
.andExpect(jsonPath("$.id", is("37bd1461-ee1a-4522-9f8c-93bab186fad3")))
.andExpect(jsonPath("$.jobStatus", is("In progress")))
.andExpect(jsonPath("$.submittedDate", is("2021-11-08T13:00:00.000+00:00")));
}

@Test
void runReindex_positive_locations() throws Exception {
var request = getReindexRequestBuilder(
Expand Down
Loading

0 comments on commit 0412a43

Please sign in to comment.