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

com.arakelian.elastic.bulk.DefaultBulkOperationFactory Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.arakelian.elastic.bulk;

import static com.arakelian.elastic.bulk.BulkOperation.VersionType.EXTERNAL;

import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.List;

import com.arakelian.core.utils.DateUtils;
import com.arakelian.dao.feature.HasId;
import com.arakelian.dao.feature.HasTimestamp;
import com.arakelian.elastic.bulk.BulkOperation.Action;
import com.arakelian.elastic.model.Index;
import com.arakelian.jackson.utils.JacksonUtils;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;

public class DefaultBulkOperationFactory implements BulkOperationFactory {
    private final Index index;
    private final String type;

    public DefaultBulkOperationFactory(final Index index, final String type) {
        this.index = index;
        this.type = type;
    }

    @Override
    public BulkOperation createBulkOperation(
            final Action action,
            final String id,
            final String source,
            final Long version) {
        return ImmutableBulkOperation.builder() //
                .action(action) //
                .index(index) //
                .type(type) //
                .id(id) //
                .source(source) //
                .version(version) //
                .versionType(EXTERNAL) //
                .build();
    }

    @Override
    public List getBulkOperations(final Action action, final T value) throws IOException {
        final String id = value.getId();
        final String source = action.hasSource() ? JacksonUtils.toString(value, false) : null;
        final ZonedDateTime versionDate = getVersionDate(action, value);
        final Long version = Long.valueOf(versionDate.toInstant().toEpochMilli());
        final BulkOperation operation = createBulkOperation(action, id, source, version);
        return Lists.newArrayList(operation);
    }

    /**
     * Returns the date that we should use as the basis of a version passed to Elastic.
     *
     * For {@link Action#CREATE}, {@link Action#INDEX} and {@link Action#UPDATE} requests, we check
     * if the value extends {@link HasTimestamp}, and use either the update date or create date if
     * provided; in all other cases, we'll fall back to use the current date.
     *
     * For {@link Action#DELETE} requests we cannot use the update or create date (as it it would
     * fail with "version conflict, current version [XXX] is higher or *equal* to the one provided
     * [XXX]". The version number we pass on a DELETE is version to be assigned to the DELETED
     * document. It is equivalent to saying, "delete any version that is OLDER than this timestamp,
     * and then use that timestamp as the new version number for the deleted document."
     *
     * @param action
     *            action to perform
     * @param value
     *            value being stored in Elastic
     * @return date that we should use as the basis of a version passed to Elastic.
     */
    protected ZonedDateTime getVersionDate(final Action action, final T value) {
        switch (action) {
        case CREATE:
        case INDEX:
        case UPDATE:
            if (value instanceof HasTimestamp) {
                final HasTimestamp hasTimestamp = (HasTimestamp) value;
                final ZonedDateTime date = MoreObjects
                        .firstNonNull(hasTimestamp.getUpdated(), hasTimestamp.getCreated());
                if (date != null) {
                    // make sure we are in UTC format
                    return DateUtils.toUtc(date);
                }
            }
            break;
        case DELETE:
        default:
            // when deleting a document from Elastic, we don't want to use the document date as our
            // timestamp (it would fail with "version conflict, current version [XXX] is higher or
            // equal to the one provided [XXX]"; that's because for deletes, the version we pass is
            // basically saying, "delete any version that is older than this timestamp"
            break;
        }

        // use current date/time
        return DateUtils.nowWithZoneUtc();
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy