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

org.hibernate.search.elasticsearch.impl.ElasticsearchNestingContextFactoryProvider Maven / Gradle / Ivy

/*
 * Hibernate Search, full-text search for your domain model
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.search.elasticsearch.impl;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.TextField;
import org.hibernate.search.engine.integration.impl.ExtendedSearchIntegrator;
import org.hibernate.search.engine.metadata.impl.EmbeddedTypeMetadata.Container;
import org.hibernate.search.engine.nesting.impl.NestingContext;
import org.hibernate.search.engine.nesting.impl.NestingContextFactory;
import org.hibernate.search.engine.nesting.impl.NestingContextFactoryProvider;
import org.hibernate.search.engine.nesting.impl.NoOpNestingContext;
import org.hibernate.search.engine.service.spi.Startable;
import org.hibernate.search.engine.spi.EntityIndexBinding;
import org.hibernate.search.indexes.spi.IndexManager;
import org.hibernate.search.spi.BuildContext;
import org.hibernate.search.util.StringHelper;

public class ElasticsearchNestingContextFactoryProvider implements NestingContextFactoryProvider, Startable {

	private ElasticsearchNestingContextFactory factory;

	@Override
	public void start(Properties properties, BuildContext context) {
		factory = new ElasticsearchNestingContextFactory( context.getUninitializedSearchIntegrator() );
	}

	@Override
	public NestingContextFactory getNestingContextFactory() {
		return factory;
	}

	private static class ElasticsearchNestingContextFactory implements NestingContextFactory {

		private final ConcurrentMap strategies = new ConcurrentHashMap<>();
		private ExtendedSearchIntegrator searchIntegrator;

		public ElasticsearchNestingContextFactory(ExtendedSearchIntegrator searchIntegrator) {
			this.searchIntegrator = searchIntegrator;
		}

		@Override
		public NestingContext createNestingContext(Class indexedEntityType) {
			ContextCreationStrategy strategy = strategies.get( indexedEntityType.getName() );

			if ( strategy == null ) {
				strategy = isMappedToElasticsearch( indexedEntityType ) ? ContextCreationStrategy.ES : ContextCreationStrategy.NO_OP;
				strategies.putIfAbsent( indexedEntityType.getName(), strategy );
			}

			return strategy.create();
		}

		private boolean isMappedToElasticsearch(Class entityType) {
			Set> queriedEntityTypesWithSubTypes = searchIntegrator.getIndexedTypesPolymorphic( new Class[] { entityType } );

			for ( Class queriedEntityType : queriedEntityTypesWithSubTypes ) {
				EntityIndexBinding binding = searchIntegrator.getIndexBinding( queriedEntityType );
				IndexManager[] indexManagers = binding.getIndexManagers();

				for ( IndexManager indexManager : indexManagers ) {
					if ( indexManager instanceof ElasticsearchIndexManager ) {
						return true;
					}
				}
			}

			return false;
		}
	}

	private enum ContextCreationStrategy {
		NO_OP {
			@Override
			NestingContext create() {
				return NoOpNestingContext.INSTANCE;
			}
		},
		ES {
			@Override
			NestingContext create() {
				return new ElasticsearchNestingContext();
			}
		};

		abstract NestingContext create();
	}

	private static class ElasticsearchNestingContext implements NestingContext {

		private Deque path = new ArrayDeque<>();

		@Override
		public void push(String fieldName, Container containerType) {
			path.push(
					new NestingStackElement(
							fieldName,
							containerType == Container.OBJECT ? null : 0
					)
			);
		}

		@Override
		public void mark(Document document) {
			String currentPath = StringHelper.join( path.descendingIterator(), "." );
			document.add( new TextField( "$nesting", currentPath, Store.NO ) );
		}

		@Override
		public void incrementCollectionIndex() {
			path.peek().increment();
		}

		@Override
		public void pop() {
			path.pop();
		}
	}

	private static class NestingStackElement {
		String field;
		Integer index;

		public NestingStackElement(String fieldName, Integer index) {
			this.field = fieldName;
			this.index = index;
		}

		@Override
		public String toString() {
			if ( index == null ) {
				return field;
			}
			else {
				return field + "[" + index + "]";
			}
		}

		void increment() {
			index = index + 1;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy