All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.metacat.main.services.search.ElasticSearchEventHandlers Maven / Gradle / Ivy

/*
 * Copyright 2016 Netflix, Inc.
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */


package com.netflix.metacat.main.services.search;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.netflix.metacat.common.MetacatRequestContext;
import com.netflix.metacat.common.dto.DatabaseDto;
import com.netflix.metacat.common.dto.PartitionDto;
import com.netflix.metacat.common.dto.TableDto;
import com.netflix.metacat.common.json.MetacatJsonLocator;
import com.netflix.metacat.common.server.events.AsyncListener;
import com.netflix.metacat.common.server.events.MetacatCreateDatabasePostEvent;
import com.netflix.metacat.common.server.events.MetacatCreateTablePostEvent;
import com.netflix.metacat.common.server.events.MetacatDeleteDatabasePostEvent;
import com.netflix.metacat.common.server.events.MetacatDeleteTablePartitionPostEvent;
import com.netflix.metacat.common.server.events.MetacatDeleteTablePostEvent;
import com.netflix.metacat.common.server.events.MetacatRenameTablePostEvent;
import com.netflix.metacat.common.server.events.MetacatSaveTablePartitionPostEvent;
import com.netflix.metacat.common.server.events.MetacatUpdateTablePostEvent;
import com.netflix.metacat.common.server.monitoring.Metrics;
import com.netflix.metacat.common.server.properties.Config;
import com.netflix.spectator.api.Registry;
import com.netflix.spectator.api.Timer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Event handlers for elastic search indexing.
 */
@Slf4j
@AsyncListener
public class ElasticSearchEventHandlers {
    private final ElasticSearchUtil es;
    private final MetacatJsonLocator metacatJsonLocator;
    private final Config config;
    private final Timer databaseCreateEventsDelayTimer;
    private final Timer databaseCreateTimer;
    private final Timer tableCreateEventsDelayTimer;
    private final Timer tableCreateTimer;
    private final Timer databaseDeleteEventsDelayTimer;
    private final Timer databaseDeleteTimer;
    private final Timer tableDeleteEventsDelayTimer;
    private final Timer tableDeleteTimer;
    private final Timer partitionDeleteEventsDelayTimer;
    private final Timer partitionDeleteTimer;
    private final Timer tableRenameEventsDelayTimer;
    private final Timer tableRenameTimer;
    private final Timer tableUpdateEventsDelayTimer;
    private final Timer tableUpdateTimer;
    private final Timer partitionSaveEventsDelayTimer;
    private final Timer partitionSaveTimer;

    /**
     * Constructor.
     *
     * @param es       elastic search util
     * @param registry registry to spectator
     * @param config   configurations
     */
    public ElasticSearchEventHandlers(final ElasticSearchUtil es,
                                      final Registry registry,
                                      final Config config) {
        this.es = es;
        this.metacatJsonLocator = new MetacatJsonLocator();
        this.config = config;
        this.databaseCreateEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "database.create");
        this.databaseCreateTimer = registry.timer(Metrics.TimerElasticSearchDatabaseCreate.getMetricName());
        this.tableCreateEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "table.create");
        this.tableCreateTimer = registry.timer(Metrics.TimerElasticSearchTableCreate.getMetricName());
        this.databaseDeleteEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "database.delete");
        this.databaseDeleteTimer = registry.timer(Metrics.TimerElasticSearchDatabaseDelete.getMetricName());
        this.tableDeleteEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "table.delete");
        this.tableDeleteTimer = registry.timer(Metrics.TimerElasticSearchTableDelete.getMetricName());
        this.partitionDeleteEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "partition.delete");
        this.partitionDeleteTimer = registry.timer(Metrics.TimerElasticSearchPartitionDelete.getMetricName());
        this.tableRenameEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "table.rename");
        this.tableRenameTimer = registry.timer(Metrics.TimerElasticSearchTableRename.getMetricName());
        this.tableUpdateEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "table.update");
        this.tableUpdateTimer = registry.timer(Metrics.TimerElasticSearchTableUpdate.getMetricName());
        this.partitionSaveEventsDelayTimer = registry.timer(Metrics.TimerElasticSearchEventsDelay.getMetricName(),
            Metrics.TagEventsType.getMetricName(), "partition.save");
        this.partitionSaveTimer = registry.timer(Metrics.TimerElasticSearchPartitionSave.getMetricName());
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatCreateDatabasePostEventHandler(final MetacatCreateDatabasePostEvent event) {
        log.debug("Received CreateDatabaseEvent {}", event);
        this.databaseCreateEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        this.databaseCreateTimer.record(() -> {
            final DatabaseDto dto = event.getDatabase();
            final ElasticSearchDoc doc = new ElasticSearchDoc(dto.getName().toString(), dto,
                event.getRequestContext().getUserName(), false);
            es.save(ElasticSearchDoc.Type.database.name(), doc.getId(), doc);
        });
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatCreateTablePostEventHandler(final MetacatCreateTablePostEvent event) {
        log.debug("Received CreateTableEvent {}", event);
        this.tableCreateEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        this.tableCreateTimer.record(() -> {
            final TableDto dto = event.getTable();
            final ElasticSearchDoc doc = new ElasticSearchDoc(dto.getName().toString(), dto,
                event.getRequestContext().getUserName(), false);
            es.save(ElasticSearchDoc.Type.table.name(), doc.getId(), doc);
        });
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatDeleteDatabasePostEventHandler(final MetacatDeleteDatabasePostEvent event) {
        log.debug("Received DeleteDatabaseEvent {}", event);
        this.databaseDeleteEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        this.databaseDeleteTimer.record(() -> {
            final DatabaseDto dto = event.getDatabase();
            es.softDelete(ElasticSearchDoc.Type.database.name(), dto.getName().toString(), event.getRequestContext());
        });
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatDeleteTablePostEventHandler(final MetacatDeleteTablePostEvent event) {
        log.debug("Received DeleteTableEvent {}", event);
        this.tableDeleteEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        this.tableDeleteTimer.record(() -> {
            final TableDto dto = event.getTable();
            es.softDelete(ElasticSearchDoc.Type.table.name(), dto.getName().toString(), event.getRequestContext());
            if (config.isElasticSearchPublishPartitionEnabled()) {
                try {
                    final List partitionIdsToBeDeleted =
                        es.getIdsByQualifiedName(ElasticSearchDoc.Type.partition.name(), dto.getName());
                    es.delete(ElasticSearchDoc.Type.partition.name(), partitionIdsToBeDeleted);
                } catch (Exception e) {
                    log.warn("Failed deleting the partitions for the dropped table/view:{}", dto.getName());
                }
            }
        });
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatDeleteTablePartitionPostEventHandler(final MetacatDeleteTablePartitionPostEvent event) {
        log.debug("Received DeleteTablePartitionEvent {}", event);
        this.partitionDeleteEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        if (config.isElasticSearchPublishPartitionEnabled()) {
            this.partitionDeleteTimer.record(() -> {
                final List partitionIds = event.getPartitionIds();
                final List esPartitionIds = partitionIds.stream()
                    .map(partitionId -> event.getName().toString() + "/" + partitionId).collect(Collectors.toList());
                es.softDelete(ElasticSearchDoc.Type.partition.name(), esPartitionIds, event.getRequestContext());
            });
        }
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatRenameTablePostEventHandler(final MetacatRenameTablePostEvent event) {
        log.debug("Received RenameTableEvent {}", event);
        this.tableRenameEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        this.tableRenameTimer.record(() -> {
            es.delete(ElasticSearchDoc.Type.table.name(), event.getName().toString());

            final TableDto dto = event.getCurrentTable();
            final ElasticSearchDoc doc = new ElasticSearchDoc(dto.getName().toString(), dto,
                event.getRequestContext().getUserName(), false);
            es.save(ElasticSearchDoc.Type.table.name(), doc.getId(), doc);
        });
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatUpdateTablePostEventHandler(final MetacatUpdateTablePostEvent event) {
        log.debug("Received UpdateTableEvent {}", event);
        this.tableUpdateEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        this.tableUpdateTimer.record(() -> {
            final TableDto dto = event.getCurrentTable();

            final ElasticSearchDoc doc = new ElasticSearchDoc(dto.getName().toString(), dto,
                event.getRequestContext().getUserName(), false);
            final ElasticSearchDoc oldDoc = es.get(ElasticSearchDoc.Type.table.name(), doc.getId());
            es.save(ElasticSearchDoc.Type.table.name(), doc.getId(), doc);
            if (config.isElasticSearchUpdateTablesWithSameUriEnabled()
                && (oldDoc == null || oldDoc.getDto() == null
                    || !Objects.equals(((TableDto) oldDoc.getDto()).getDataMetadata(), dto.getDataMetadata()))) {
                updateEntitiesWithSameUri(ElasticSearchDoc.Type.table.name(),
                    dto, event.getRequestContext().getUserName());
            }
        });
    }

    private void updateEntitiesWithSameUri(final String metadataType, final TableDto dto,
                                           final String userName) {
        if (dto.isDataExternal()) {
            final List ids = es.getTableIdsByUri(metadataType, dto.getDataUri())
                .stream().filter(s -> !s.equals(dto.getName().toString())).collect(Collectors.toList());
            if (!ids.isEmpty()) {
                log.info("ElasticSearch table updates({}) with same uri {} (Table:{})",
                    ids.size(), dto.getDataUri(), dto.getName());
                final ObjectNode node = metacatJsonLocator.emptyObjectNode();
                node.set(ElasticSearchDoc.Field.DATA_METADATA, dto.getDataMetadata());
                node.put(ElasticSearchDoc.Field.USER, userName);
                node.put(ElasticSearchDoc.Field.TIMESTAMP, java.time.Instant.now().toEpochMilli());
                es.updates(ElasticSearchDoc.Type.table.name(), ids, node);
            }
        }
    }

    /**
     * Subscriber.
     *
     * @param event event
     */
    @EventListener
    public void metacatSaveTablePartitionPostEventHandler(final MetacatSaveTablePartitionPostEvent event) {
        log.debug("Received SaveTablePartitionEvent {}", event);
        this.partitionSaveEventsDelayTimer
            .record(System.currentTimeMillis() - event.getRequestContext().getTimestamp(), TimeUnit.MILLISECONDS);
        if (config.isElasticSearchPublishPartitionEnabled()) {
            this.partitionSaveTimer.record(() -> {
                final List partitionDtos = event.getPartitions();
                final MetacatRequestContext context = event.getRequestContext();
                final List docs = partitionDtos.stream()
                    .map(dto -> new ElasticSearchDoc(dto.getName().toString(), dto, context.getUserName(), false))
                    .collect(Collectors.toList());
                es.save(ElasticSearchDoc.Type.partition.name(), docs);
            });
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy