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

com.arakelian.elastic.bulk.BulkOperation 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 org.apache.commons.lang3.StringUtils;
import org.immutables.value.Value;

import com.arakelian.core.feature.Nullable;
import com.arakelian.elastic.model.Index;
import com.arakelian.elastic.model.Mapping;
import com.arakelian.json.JsonFilter;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.base.Preconditions;

/**
 * Represents a source document that will be indexed into Elastic.
 */
@Value.Immutable(copy = false)
public abstract class BulkOperation {
    // see: https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html
    public static enum Action {
        CREATE(true), //
        DELETE(false), //
        INDEX(true), //
        UPDATE(true);

        private final boolean hasSource;

        private Action(final boolean hasSource) {
            this.hasSource = hasSource;
        }

        public final boolean hasSource() {
            return hasSource;
        }

        @Override
        @JsonValue
        public String toString() {
            return this.name().toLowerCase();
        }
    }

    // see: https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html
    public enum VersionType {
        INTERNAL, //
        EXTERNAL, //
        EXTERNAL_GTE;

        @Override
        @JsonValue
        public String toString() {
            return this.name().toLowerCase();
        }
    }

    /**
     * Returns mapping type within index.
     *
     * @return mapping type within index.
     */
    public abstract Action getAction();

    @Nullable
    @Value.Derived
    @Value.Auxiliary
    public String getCompactSource() {
        final String source = getSource();
        if (source != null && source.indexOf('\n') != -1) {
            return JsonFilter.compactQuietly(source);
        }
        return source;
    }

    /**
     * Returns the id of the document.
     *
     * @return id of the document.
     */
    public abstract String getId();

    /**
     * Returns index that this document will be indexed into.
     *
     * @return index that this document will be indexed into.
     */
    public abstract Index getIndex();

    @Value.Derived
    @Value.Auxiliary
    public String getOperation() {
        final StringBuilder buf = new StringBuilder();
        addActionAndMetadata(buf);
        if (getAction().hasSource()) {
            buf.append(getCompactSource()).append('\n');
        }
        return buf.toString();
    }

    /**
     * Returns source JSON document that will be indexed by {@link BulkIndexer}
     *
     * @return source JSON document that will be indexed by {@link BulkIndexer}
     */
    @Nullable
    @Value.Auxiliary
    public abstract String getSource();

    /**
     * Returns mapping type within index.
     *
     * @return mapping type within index.
     */
    public abstract String getType();

    @Nullable
    public abstract Long getVersion();

    @Nullable
    @Value.Default
    public VersionType getVersionType() {
        return getVersion() != null ? VersionType.EXTERNAL : null;
    }

    private void addActionAndMetadata(final StringBuilder buf) {
        final Action action = getAction();

        buf.append('{');
        buf.append("\"").append(action.toString()).append("\"").append(':');
        buf.append('{');

        buf.append("\"_index\"").append(':');
        buf.append('"').append(getIndex().getName()).append('"');

        buf.append(',');
        buf.append("\"_type\"").append(':');
        buf.append('"').append(getType()).append('"');

        buf.append(',');
        buf.append("\"_id\"").append(':');
        buf.append('"').append(getId()).append('"');

        if (getVersion() != null) {
            buf.append(',');
            buf.append("\"_version\"").append(':');
            buf.append(getVersion());
            if (getVersionType() != null) {
                buf.append(',');
                buf.append("\"version_type\"").append(':');
                buf.append('"').append(getVersionType()).append('"');
            }
        }

        buf.append('}');
        buf.append('}');
        buf.append('\n');
    }

    @Value.Check
    protected void checkSource() {
        if (getAction().hasSource()) {
            final String source = getCompactSource();
            Preconditions.checkState(source != null && source.length() != 0, "Source must be non-empty");
            Preconditions.checkState(
                    source.indexOf('\n') == -1,
                    "Newlines are not allowed in source JSON document when using Elastic bulk API");
            Preconditions.checkState(
                    !StringUtils.equals(getType(), Mapping._DEFAULT_),
                    "It is forbidden to index into the _default_ mapping");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy