Java ElasticsearchClient: Conditionally mapping result hits to a certain object depending on a field or index

62 Views Asked by At

Using the Java ElasticsearchClient, is it possible to create a custom mapper, so that depending on a certain field (or index) of the result hit, a different object is mapped?

I have several indices with different, but very similar documents. The base properties are the same in all of them. And if I query for a list of IDs, I ususally query for (similar) objects in different indices. Ideally I want to have a result list List<? extends BaseDocument> with potentially different objects in it, all of them extending my BaseDocument.

Of course, one approach would be to this in my BaseDocument, which will store all unmapped properties in a map.

@JsonAnyGetter
@JsonAnySetter
protected final Map<String, Object> properties = new LinkedHashMap<>();

And then, in SpecialDocument, I can access those properties by

public getSpecialProperty() {
    return super.properties.get("specialProperty");
}

Another way would be to map all result hits just to a Map, and then checking the contents of the map and using a custom ObjectMapper to map this map back to my domain objects:

public List<? extends BaseDocument> search(final List<String> indices, final Query query) throws IOException {
    final ObjectMapper objectMapper = new ObjectMapper();
    final SearchResponse<Map> searchResponse = elasticsearchClient.search(s -> s.index(indices).query(query), Map.class);
    return searchResponse.hits().hits().stream().map(
        hit -> {
            switch (hit.source().get("documentType").toString()) {
                case "specialDocument":
                    return objectMapper.convertValue(hit.source(), SpecialDocument.class);
                case "anotherSpecialDocument":
                    return objectMapper.convertValue(hit.source(), AnotherSpecialDocument.class);
                default:
                    return objectMapper.convertValue(hit.source(), BaseDocument.class);
            }
        }
    ).toList();
}

Now, this is mapping the result twice, one time to a Map, another time to a concrete object.

Is there a way to pass a mapper to the ElasticsearchClient (instead of the JsonpMapper, for example?), where I can define conditions to map the result directly to a certain object, instead of treating all results as the same?

0

There are 0 best solutions below