Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Elasticsearch: Multiple Index with same Document

I'm using spring-data-elasticsearch and for the beginning everything works fine.

@Document( type = "products", indexName = "empty" )
public class Product
{
...
}

public interface ProductRepository extends ElasticsearchRepository<Product, String>
{
...
}

In my model i can search for products.

@Autowired
private ProductRepository repository;
...
repository.findByIdentifier( "xxx" ).getCategory() );

So, my problem is - I've the same Elasticsearch type in different indices and I want to use the same document for all queries. I can handle more connections via a pool - but I don't have any idea how I can implement this.

I would like to have, something like that:

ProductRepository customerRepo = ElasticsearchPool.getRepoByCustomer("abc", ProductRepository.class);
repository.findByIdentifier( "xxx" ).getCategory();

Is it possible to create a repository at runtime, with an different index ?

Thanks a lot Marcel

like image 582
Marcel Avatar asked Feb 11 '15 22:02

Marcel


Video Answer


1 Answers

Yes. It's possible with Spring. But you should use ElasticsearchTemplate instead of Repository.

For example. I have two products. They are stored in different indices.

@Document(indexName = "product-a", type = "product")
public class ProductA {

    @Id
    private String id;

    private String name;

    private int value;

    //Getters and setters
}

@Document(indexName = "product-b", type = "product")
public class ProductB {

    @Id
    private String id;

    private String name;

    //Getters and setters

}

Suppose if they have the same type, so they have the same fields. But it's not necessary. Two products can have totally different fields.

I have two repositories:

public interface ProductARepository extends ElasticsearchRepository<ProductA, String> {
}


public interface ProductBRepository
    extends ElasticsearchRepository<ProductB, String> {


}

It's not necessary too. Only for testing. The fact that ProductA is stored in "product-a" index and ProductB is stored in "product-b" index.

How to query two(ten, dozen) indices with the same type?

Just build custom repository like this

@Repository
public class CustomProductRepositoryImpl {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    public List<ProductA> findProductByName(String name) {
        MatchQueryBuilder queryBuilder = QueryBuilders.matchPhrasePrefixQuery("name", name);

        //You can query as many indices as you want
        IndicesQueryBuilder builder = QueryBuilders.indicesQuery(queryBuilder, "product-a", "product-b");

        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();

        return elasticsearchTemplate.query(searchQuery, response -> {
            SearchHits hits = response.getHits();
            List<ProductA> result = new ArrayList<>();
            Arrays.stream(hits.getHits()).forEach(h -> {
                Map<String, Object> source = h.getSource();
                //get only id just for test
                ProductA productA = new ProductA()
                        .setId(String.valueOf(source.getOrDefault("id", null)));
                result.add(productA);
            });
            return result;
        });
    }

}

You can search as many indices as you want and you can transparently inject this behavior into ProductARepository adding custom behavior to single repositories

Second solution is to use indices aliases, but you had to create custom model or custom repository too.

like image 95
Vadeg Avatar answered Oct 19 '22 01:10

Vadeg