Skip to content

Commit

Permalink
feat(indexing): Persist subjects/contributors/classifications manuall…
Browse files Browse the repository at this point in the history
…y instead of a database trigger (#698)

* feat(indexing): Persist subjects/contributors/classifications manually instead of a database trigger

- Remove database trigger
- Add entities persisting on indexing
- Add entities persisting on re-indexing

Implements: MSEARCH-887

(cherry picked from commit 454cffc)
  • Loading branch information
viacheslavkol committed Dec 6, 2024
1 parent 0288b1b commit e66b169
Show file tree
Hide file tree
Showing 53 changed files with 1,376 additions and 141 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## v4.0.2 2024-12-06
### Features
* Move Instance sub-entities population from database trigger to code ([MSEARCH-887](https://folio-org.atlassian.net/browse/MSEARCH-887))

### Bug fixes

### Dependencies
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/folio/search/cql/CqlTermQueryConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.folio.search.cql.builders.TermQueryBuilder;
import org.folio.search.exception.RequestValidationException;
import org.folio.search.exception.ValidationException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.folio.search.utils.SearchUtils.SOURCE_CONSORTIUM_PREFIX;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
Expand All @@ -22,6 +23,7 @@
import org.folio.search.domain.dto.ResourceEventType;
import org.folio.search.model.types.ReindexEntityType;
import org.folio.search.model.types.ResourceType;
import org.folio.search.service.InstanceChildrenResourceService;
import org.folio.search.service.consortium.ConsortiumTenantExecutor;
import org.folio.search.service.reindex.jdbc.MergeRangeRepository;
import org.folio.search.service.reindex.jdbc.ReindexJdbcRepository;
Expand All @@ -39,13 +41,16 @@ public class PopulateInstanceBatchInterceptor implements BatchInterceptor<String
private final Map<ReindexEntityType, MergeRangeRepository> repositories;
private final ConsortiumTenantExecutor executionService;
private final SystemUserScopedExecutionService systemUserScopedExecutionService;
private final InstanceChildrenResourceService instanceChildrenResourceService;

public PopulateInstanceBatchInterceptor(List<MergeRangeRepository> repositories,
ConsortiumTenantExecutor executionService,
SystemUserScopedExecutionService systemUserScopedExecutionService) {
SystemUserScopedExecutionService systemUserScopedExecutionService,
InstanceChildrenResourceService instanceChildrenResourceService) {
this.repositories = repositories.stream().collect(Collectors.toMap(ReindexJdbcRepository::entityType, identity()));
this.executionService = executionService;
this.systemUserScopedExecutionService = systemUserScopedExecutionService;
this.instanceChildrenResourceService = instanceChildrenResourceService;
}

@Override
Expand All @@ -55,7 +60,7 @@ public ConsumerRecords<String, ResourceEvent> intercept(ConsumerRecords<String,
.filter(r -> isInstanceEvent(r.value()))
.collect(Collectors.groupingBy(ConsumerRecord::key));

List<ResourceEvent> consumerRecords = new ArrayList<>();
var consumerRecords = new ArrayList<ResourceEvent>();
for (var entry : recordsById.entrySet()) {
var list = entry.getValue();
if (list.size() > 1) {
Expand Down Expand Up @@ -113,6 +118,11 @@ private void process(String tenant, List<ResourceEvent> batch) {
if (!idsToDrop.isEmpty()) {
repository.deleteEntities(idsToDrop);
}

if (ResourceType.INSTANCE.getName().equals(recordCollection.getKey())) {
var noShadowCopiesInstanceEvents = recordByOperation.values().stream().flatMap(Collection::stream).toList();
instanceChildrenResourceService.persistChildren(tenant, noShadowCopiesInstanceEvents);
}
}

}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/folio/search/model/BrowseResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.CollectionUtils;

@Data
@NoArgsConstructor
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/folio/search/model/SearchResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.CollectionUtils;

@Data
@NoArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.folio.search.domain.dto.ResourceEvent;
import org.folio.search.domain.dto.ResourceEventType;
import org.folio.search.model.event.SubResourceEvent;
import org.folio.search.service.consortium.ConsortiumTenantProvider;
import org.folio.search.service.converter.preprocessor.extractor.ChildResourceExtractor;
import org.folio.spring.tools.kafka.FolioMessageProducer;
import org.springframework.stereotype.Component;
Expand All @@ -27,6 +30,7 @@ public class InstanceChildrenResourceService {

private final FolioMessageProducer<SubResourceEvent> messageProducer;
private final List<ChildResourceExtractor> resourceExtractors;
private final ConsortiumTenantProvider consortiumTenantProvider;

public void sendChildrenEvent(ResourceEvent event) {
var needChildrenEvent = false;
Expand Down Expand Up @@ -62,15 +66,15 @@ public List<ResourceEvent> extractChildren(ResourceEvent event) {
var events = new LinkedList<ResourceEvent>();

if (isUpdateEventForResourceSharing(event)) {
for (ChildResourceExtractor resourceExtractor : resourceExtractors) {
for (var resourceExtractor : resourceExtractors) {
events.addAll(resourceExtractor.prepareEventsOnSharing(event));
}
} else if (startsWith(getResourceSource(event), SOURCE_CONSORTIUM_PREFIX)) {
log.debug(
"processChildren::Finished instance children event processing. No additional action for shadow instance.");
return events;
} else {
for (ChildResourceExtractor resourceExtractor : resourceExtractors) {
for (var resourceExtractor : resourceExtractors) {
events.addAll(resourceExtractor.prepareEvents(event));
}
}
Expand All @@ -81,4 +85,20 @@ public List<ResourceEvent> extractChildren(ResourceEvent event) {
return events;
}

public void persistChildren(String tenantId, List<ResourceEvent> events) {
var shared = consortiumTenantProvider.isCentralTenant(tenantId);
resourceExtractors.forEach(resourceExtractor -> resourceExtractor.persistChildren(shared, events));
}

public void persistChildrenOnReindex(String tenantId, List<Map<String, Object>> instances) {
var events = instances.stream()
.map(instance -> new ResourceEvent()
.id(instance.get("id").toString())
.type(ResourceEventType.REINDEX)
.tenant(tenantId)
._new(instance))
.toList();
persistChildren(tenantId, events);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.function.Consumer;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.folio.search.configuration.properties.StreamIdsProperties;
import org.folio.search.cql.CqlSearchQueryConverter;
import org.folio.search.exception.SearchServiceException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import static java.util.Collections.emptyList;
import static java.util.function.Function.identity;
import static java.util.stream.Stream.concat;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.folio.search.model.types.ResourceType.INSTANCE;
import static org.folio.search.utils.CollectionUtils.toLinkedHashMap;
import static org.opensearch.index.query.QueryBuilders.existsQuery;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.folio.search.domain.dto.CallNumberBrowseItem;
import org.folio.search.domain.dto.Instance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import static java.lang.Boolean.TRUE;
import static java.util.Collections.singletonList;
import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.apache.commons.collections4.CollectionUtils.isEmpty;
import static org.folio.search.model.types.CallNumberTypeSource.FOLIO;
import static org.folio.search.utils.CollectionUtils.mergeSafelyToList;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static org.folio.search.utils.SearchUtils.AUTHORITY_ID_FIELD;
import static org.folio.search.utils.SearchUtils.MISSING_FIRST_PROP;
import static org.folio.search.utils.SearchUtils.MISSING_LAST_PROP;
import static org.folio.search.utils.SearchUtils.SUBJECT_SOURCE_ID_FIELD;
import static org.folio.search.utils.SearchUtils.SUBJECT_TYPE_ID_FIELD;
import static org.opensearch.index.query.QueryBuilders.boolQuery;
import static org.opensearch.index.query.QueryBuilders.matchAllQuery;
import static org.opensearch.index.query.QueryBuilders.termQuery;
Expand Down Expand Up @@ -32,9 +34,6 @@
@RequiredArgsConstructor
public class SubjectBrowseService extends AbstractBrowseServiceBySearchAfter<SubjectBrowseItem, SubjectResource> {

private static final String SUBJECT_SOURCE_ID_FIELD = "sourceId";
private static final String SUBJECT_TYPE_ID_FIELD = "typeId";

private ConsortiumSearchHelper consortiumSearchHelper;

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.folio.search.model.converter.ConversionContext;
import org.folio.search.model.metadata.SearchFieldDescriptor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,81 @@
package org.folio.search.service.converter.preprocessor.extractor;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static org.apache.commons.collections4.MapUtils.getObject;
import static org.folio.search.utils.SearchConverterUtils.getNewAsMap;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.folio.search.domain.dto.ResourceEvent;
import org.folio.search.domain.dto.ResourceEventType;
import org.folio.search.service.reindex.jdbc.InstanceChildResourceRepository;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
public abstract class ChildResourceExtractor {

private final InstanceChildResourceRepository repository;

public abstract List<ResourceEvent> prepareEvents(ResourceEvent resource);

public abstract List<ResourceEvent> prepareEventsOnSharing(ResourceEvent resource);

public abstract boolean hasChildResourceChanges(ResourceEvent event);

protected abstract List<Map<String, Object>> constructRelations(boolean shared, ResourceEvent event,
List<Map<String, Object>> entities);

protected abstract Map<String, Object> constructEntity(Map<String, Object> entityProperties);

protected abstract String childrenFieldName();

@Transactional
public void persistChildren(boolean shared, List<ResourceEvent> events) {
var instanceIdsForDeletion = events.stream()
.filter(event -> event.getType() != ResourceEventType.CREATE && event.getType() != ResourceEventType.REINDEX)
.map(ResourceEvent::getId)
.toList();
if (!instanceIdsForDeletion.isEmpty()) {
repository.deleteByInstanceIds(instanceIdsForDeletion);
}

public interface ChildResourceExtractor {
var eventsForSaving = events.stream()
.filter(event -> event.getType() != ResourceEventType.DELETE)
.toList();
if (eventsForSaving.isEmpty()) {
return;
}

List<ResourceEvent> prepareEvents(ResourceEvent resource);
var entities = new HashSet<Map<String, Object>>();
var relations = new LinkedList<Map<String, Object>>();
eventsForSaving.forEach(event -> {
var entitiesFromEvent = extractEntities(event);
relations.addAll(constructRelations(shared, event, entitiesFromEvent));
entities.addAll(entitiesFromEvent);
});
repository.saveAll(entities, relations);
}

List<ResourceEvent> prepareEventsOnSharing(ResourceEvent resource);
private List<Map<String, Object>> extractEntities(ResourceEvent event) {
var entities = getChildResources(getNewAsMap(event));
return entities.stream()
.map(this::constructEntity)
.filter(Objects::nonNull)
.toList();
}

boolean hasChildResourceChanges(ResourceEvent event);
@SuppressWarnings("unchecked")
protected Set<Map<String, Object>> getChildResources(Map<String, Object> event) {
var object = getObject(event, childrenFieldName(), emptyList());
if (object == null) {
return emptySet();
}
return new HashSet<>((List<Map<String, Object>>) object);
}
}
Loading

0 comments on commit e66b169

Please sign in to comment.