'How can I match search result in Elasticsearch to the Java Model?

Firstly, my project has MinIO server where I use minio api to upload my files via spring boot application. The MinIO server integrated with Elasticsearch. When I uploaded a file, MinIO automatically update Elasticsearch minio_events index (I have configured this settings before). I want to run following query in my spring boot application and match result into File.java:

POST http://localhost:9200/minio_events/_search

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "Records.s3.object.userMetadata.X-Amz-Meta-Filename": "myfile.txt"
                    }
                },
                {
                    "match": {
                        "Records.s3.object.userMetadata.X-Amz-Meta-User_id": "40b3c4e0-fea8-4aca-9dec-b4b905f33df0"
                    }
                }
            ]
        }
    },
    "fields": [
        "Records.s3.object.userMetadata.X-Amz-Meta-Filename",
        "Records.s3.object.userMetadata.X-Amz-Meta-Description",
        "Records.s3.object.userMetadata.X-Amz-Meta-Foldername",
        "Records.s3.object.userMetadata.X-Amz-Meta-Tags",
        "Records.s3.object.userMetadata.X-Amz-Meta-User_id"
    ],
    "_source": false
}

The query result is:

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.7260925,
        "hits": [
            {
                "_index": "minio_events",
                "_type": "_doc",
                "_id": "AUuxte4_W8625RK6e6oT7tCJmJkSQJ0L9LGx6eAf0Dw=",
                "_score": 1.7260925,
                "fields": {
                    "Records.s3.object.userMetadata.X-Amz-Meta-Foldername": [
                        "helloworld"
                    ],
                    "Records.s3.object.userMetadata.X-Amz-Meta-Description": [
                        "des"
                    ],
                    "Records.s3.object.userMetadata.X-Amz-Meta-User_id": [
                        "40b3c4e0-fea8-4aca-9dec-b4b905f33df0"
                    ],
                    "Records.s3.object.userMetadata.X-Amz-Meta-Filename": [
                        "MyFile.txt"
                    ],
                    "Records.s3.object.userMetadata.X-Amz-Meta-Tags": [
                        "hello,world"
                    ]
                }
            }
        ]
    }
}

In my Spring Boot App, I wrote following repository class to fetch Elasticsearch results.

CustomFileRepository.java:

package com.oktaykcr.fileservice.repository;

import com.oktaykcr.fileservice.model.File;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class CustomFileRepository {

    private final ElasticsearchOperations elasticsearchOperations;

    private final List<String> fields = List.of(
            "Records.s3.object.userMetadata.X-Amz-Meta-Filename",
            "Records.s3.object.userMetadata.X-Amz-Meta-Description",
            "Records.s3.object.userMetadata.X-Amz-Meta-Foldername",
            "Records.s3.object.userMetadata.X-Amz-Meta-Tags",
            "Records.s3.object.userMetadata.X-Amz-Meta-User_id"
    );

    public CustomFileRepository(ElasticsearchOperations elasticsearchOperations) {
        this.elasticsearchOperations = elasticsearchOperations;
    }

    public List<File> findByFileNameAndUserId(String fileName, String userId) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("Records.s3.object.userMetadata.X-Amz-Meta-Filename", fileName))
                .must(QueryBuilders.matchQuery("Records.s3.object.userMetadata.X-Amz-Meta-User_id", userId));

        Query query = new NativeSearchQuery(queryBuilder);
        query.setFields(fields);

        SearchHits<File> result = elasticsearchOperations.search(query, File.class);

        if(result.isEmpty()) {
            return Collections.emptyList();
        }

        List<File> files = result.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
        return files;
    }
}

File.java:

package com.oktaykcr.fileservice.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.util.List;

@Document(indexName = "minio_events")
public class File {

    @Id
    private String id;

    @Field(type = FieldType.Object, value = "fields")
    private Fields fields;

    public File() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Fields getFields() {
        return fields;
    }

    public void setFields(Fields fields) {
        this.fields = fields;
    }

    static class Fields {

        @Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Foldername")
        public List<String> folderName;

        @Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Description")
        public List<String> description;

        @Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-User_id")
        public List<String> userId;

        @Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Filename")
        public List<String> fileName;

        @Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Tags")
        public List<String> tags;

        public Fields() {
        }

        public List<String> getFolderName() {
            return folderName;
        }

        public void setFolderName(List<String> folderName) {
            this.folderName = folderName;
        }

        public List<String> getDescription() {
            return description;
        }

        public void setDescription(List<String> description) {
            this.description = description;
        }

        public List<String> getUserId() {
            return userId;
        }

        public void setUserId(List<String> userId) {
            this.userId = userId;
        }

        public List<String> getFileName() {
            return fileName;
        }

        public void setFileName(List<String> fileName) {
            this.fileName = fileName;
        }

        public List<String> getTags() {
            return tags;
        }

        public void setTags(List<String> tags) {
            this.tags = tags;
        }
    }
}

However, the result of List<File> files = customFileRepository.findByFileNameAndUserId(fileName, userId); is:

result = {ArrayList@15401}  size = 1
 0 = {File@15403} 
  id = "AUuxte4_W8625RK6e6oT7tCJmJkSQJ0L9LGx6eAf0Dw="
  fields = null

id was mapped by @Document model but fields was not.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source