lo_ol
lo_ol

Reputation: 35

Return only nested field from query in ElasticSearch Spring project

I have the following POJOs

@Document(indexName = "person", type = "user")
public class Person {

    @Id
    private String id;

    @Field(type = FieldType.String)
    private String name;

    @Field(type = FieldType.Nested)
    private List<Car> car;

// getter/setter

}
public class Car {

    @Field(type = FieldType.String)
    private String name;

    @Field(type = FieldType.String)
    private String model;

// getter/setter
}

And in the class below I want to retrieve the nested field "cars" directly for a given Person with the name passed as parameter but it returns a List with null value.

public class ElasticsearchRepo {

    private ElasticsearchOperations op;

    public List<Car> getCars(String name) {
        String[] includeFields = new String[]{"car"};
        String[] excludeFields = null;

        NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("name", name))
            .withSourceFilter(new FetchSourceFilter(includeFields, excludeFields)).build();

        SearchHits<Car> searchHits = op.search(query, Car.class, IndexCoordinates.of("person"));

        return customerSearchHits.getSearchHits().stream().map(s -> s.getContent().getCars())
            .collect(Collectors.toList());
    }

However, if in the searchHits code above I change the class to Person as shown below, I will get returned the pojo Person where the property "cars" is the only one filled in (all other properties are retrieved as null):

 SearchHits<Person> searchHits = op
            .search(query, Person.class, IndexCoordinates.of("person"));

But how may I retrieve directly the nested property cars?

Upvotes: 1

Views: 1067

Answers (1)

Abacus
Abacus

Reputation: 19431

When querying the person index, Elasticsearch will return Person documents - with only the fields that you defined in the sourcefilter. And Spring Data Elasticsearch maps these documents to the given entity. But it cannot map a source docuument with a car property toa class having name and model properties. That's why in your first case the returned persons are mapped to empty objects.

The second way you have is the correct one: retrieve the persons and extract the cars from these objects.

If you like to do it with streams:

List<Car> cars = operations.search(query, Person.class, IndexCoordinates.of("person"))
    .stream().map(SearchHit::getContent)
    .flatMap(person -> person.getCar().stream())
    .collect(Collectors.toList());

Upvotes: 1

Related Questions