package org.molgenis.data.elasticsearch; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchType; import org.molgenis.data.Entity; import org.molgenis.data.EntityCollection; import org.molgenis.data.Query; import org.molgenis.data.elasticsearch.request.SearchRequestGenerator; import org.molgenis.data.elasticsearch.util.ElasticsearchUtils; import org.molgenis.data.meta.model.EntityType; import org.molgenis.data.support.BatchingQueryResult; import org.molgenis.data.support.EntityTypeUtils; import java.util.List; import java.util.function.Consumer; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; import static org.molgenis.data.DataConverter.convert; import static org.molgenis.data.elasticsearch.util.MapperTypeSanitizer.sanitizeMapperType; /** * Retrieve search results in batches. Note: We do not use Elasticsearch scan & scroll, because scrolling is not * intended for real time user request: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current * /search-request-scroll.html */ class ElasticsearchEntityIterable extends BatchingQueryResult<Entity> implements EntityCollection { private static final int BATCH_SIZE = 1000; private final EntityType entityType; private final ElasticsearchEntityFactory elasticsearchEntityFactory; private final SearchRequestGenerator searchRequestGenerator; private final String indexName; private final String type; private final ElasticsearchUtils elasticsearchFacade; ElasticsearchEntityIterable(Query<Entity> q, EntityType entityType, ElasticsearchUtils elasticsearchFacade, ElasticsearchEntityFactory elasticsearchEntityFactory, SearchRequestGenerator searchRequestGenerator, String indexName) { super(BATCH_SIZE, q); this.entityType = requireNonNull(entityType); this.elasticsearchFacade = requireNonNull(elasticsearchFacade); this.elasticsearchEntityFactory = requireNonNull(elasticsearchEntityFactory); this.searchRequestGenerator = requireNonNull(searchRequestGenerator); this.indexName = requireNonNull(indexName); this.type = sanitizeMapperType(entityType.getName()); } @Override protected List<Entity> getBatch(Query<Entity> q) { Consumer<SearchRequestBuilder> searchRequestBuilderConsumer = searchRequestBuilder -> searchRequestGenerator .buildSearchRequest(searchRequestBuilder, type, SearchType.QUERY_AND_FETCH, q, null, null, null, entityType); return elasticsearchFacade.searchForIds(searchRequestBuilderConsumer, q.toString(), type, indexName) .map(idString -> convert(idString, entityType.getIdAttribute())) .map(idObject -> elasticsearchEntityFactory.getReference(entityType, idObject)).collect(toList()); } @Override public Iterable<String> getAttributeNames() { return EntityTypeUtils.getAttributeNames(entityType.getAtomicAttributes()); } @Override public boolean isLazy() { return true; } }