ElasticsearchService.java

/*
 * Copyright 2020 Global Crop Diversity Trust
 *
 * 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 org.gringlobal.service;

import java.beans.Transient;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.elasticsearch.client.indices.GetIndexResponse;
import org.genesys.blocks.model.EmptyModel;
import org.genesys.blocks.model.filters.EmptyModelFilter;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import com.querydsl.core.types.Predicate;

/**
 * The Interface ElasticsearchService.
 */
public interface ElasticsearchService {

	/**
	 * Makes sure indices are ready and up-to-date on startup.
	 *
	 * @param <R> the generic type
	 * @param clazz the clazz
	 */
	<R extends EmptyModel> void indexEntity(Class<R> clazz);

	/**
	 * Index entity.
	 *
	 * @param <R> the generic type
	 * @param clazz the model class
	 * @param reindexBatchSize custom batch size
	 */
	<R extends EmptyModel> void indexEntity(Class<R> clazz, int reindexBatchSize);

	/**
	 * Reindex.
	 *
	 * @param <R> the generic type
	 * @param clazz the clazz
	 */
	<R> void reindex(Class<R> clazz);

	/**
	 * Update.
	 *
	 * @param <R> the generic type
	 * @param clazz the clazz
	 * @param ids the ids
	 */
	<R> void update(Class<R> clazz, Collection<Long> ids);

	/**
	 * Async update.
	 *
	 * @param <R> the generic type
	 * @param clazz the clazz
	 * @param bucket the bucket
	 */
	<R> void asyncUpdate(Class<R> clazz, Collection<Long> bucket);

	/**
	 * Term statistics auto.
	 * @param filters the filters
	 * @param instcode the instcode
	 * @param i the i
	 *
	 * @return the term result
	 * @throws SearchException the search exception
	 */
	TermResult termStatisticsAuto(Class<? extends EmptyModel> clazz, EmptyModelFilter<?, ?> filters, int size, String term) throws SearchException;
	Map<String, TermResult> termStatisticsAuto(Class<? extends EmptyModel> clazz, EmptyModelFilter<?, ?> filters, int size, String... terms) throws SearchException;

	TermResult termStatistics(Class<? extends EmptyModel> clazz, EmptyModelFilter<?, ?> filters, int size, String term) throws SearchException;
	Map<String, TermResult> termStatistics(Class<? extends EmptyModel> clazz, EmptyModelFilter<?, ?> filters, int size, String... terms) throws SearchException;

	void realias(String aliasName, String indexPrefix, String targetIndexName);

	void addAlias(String aliasName, String indexName);

	void deleteAlias(String aliasName);

	void deleteIndex(String indexName);

	void reindexAll();

	<T extends EmptyModel> void reindex(Class<T> clazz, EmptyModelFilter<?, ?> filter);

	List<Class<?>> getIndexedEntities();

	long count(Class<?> clazz, EmptyModelFilter<?, ?> filter) throws SearchException;

	/**
	 * Wait until X records match specified filter in ES.
	 *
	 * @param clazz
	 * @param filter
	 * @param mustHaveCount
	 * @throws InterruptedException
	 */
	long waitForCount(Class<? extends EmptyModel> clazz, EmptyModelFilter<?, ?> filter, int mustHaveCount) throws SearchException;

	/**
	 * Count missing values for all fields of specified class.
	 * @param clazz the index class
	 * @param filter the EmptyModelFilter<?, ?> filter
	 * @return the map of all JSON paths with their missing value
	 */
	Map<String, Long> countMissingValues(Class<? extends EmptyModel> clazz, EmptyModelFilter<?, ?> filter) throws SearchException;

	<T extends EmptyModel> Page<T> findAll(Class<T> clazz, EmptyModelFilter<?, ?> filter, Pageable page) throws SearchException;

	<T extends EmptyModel> Page<T> findAll(Class<T> clazz, EmptyModelFilter<?, ?> filter, Predicate predicate, Pageable page) throws SearchException;

	
	public static interface IEntityLoader<T> {
		List<T> loadEntities(List<Long> entityIds);
	}

	/**
	 * The usual search, but with a custom entity loader
	 */
	<T extends EmptyModel> Page<T> findAll(Class<T> clazz, EmptyModelFilter<?, ?> filter, Predicate predicate, Pageable page, IEntityLoader<T> entityLoader, String... boostFields) throws SearchException;
	
	/**
	 * Remove matching documents from index
	 *
	 * @param clazz
	 * @param filter
	 */
	<T extends EmptyModel> void remove(Class<T> clazz, EmptyModelFilter<?, ?> filter) throws SearchException;

	/**
	 * Load all indices for the specified collection prefix.
	 *
	 * @throws IOException
	 */
	GetIndexResponse listIndices() throws IOException;

	public static class TermResult {

		private List<Term> terms;

		private Long total;
		private long other;
		private Long missing;

		public TermResult(String name, Long total, List<Term> terms, long other) {
			this.terms = terms;
			this.total = total;
			this.other = other;
			this.missing = total - terms.stream().map(Term::getCount).mapToLong(Long::longValue).sum() - other;
			if (missing <= 0) {
				// We have some terms (storage) where the total is not the total number of all
				// storage options, but count of accessions
				missing = null;
			}
		}

		public List<Term> getTerms() {
			return terms;
		}

		public Long getTotal() {
			return total;
		}

		@Transient
		public Long getTotalCount() {
			return total;
		}

		public long getOther() {
			return other;
		}

		public Long getMissing() {
			return missing;
		}
	}

	public static class Term {

		private String term;
		private long count;

		public Term(String term, long count) {
			this.term = term;
			this.count = count;
		}

		public String getTerm() {
			return term;
		}

		public long getCount() {
			return count;
		}
	}

	/**
	 * Delete all documents from the specified index
	 * 
	 * @param <R> the type
	 * @param clazz realias target
	 * @throws SearchException
	 */
	<R> void removeAll(Class<R> clazz) throws SearchException;
}