2
votes

I have created an index (house) with a type "apartments" that contains 20 documents. I uploaded the Json as a binary file into elasticsearch using postman. I have a Spring Boot project that has the following classes:

  1. EsConfig.java - I have configured the clustername which is the default name in the application.properties file.

    @Configuration
    @EnableElasticsearchRepositories(basePackages = "com.search.repository")
    public class EsConfig {
    
    @Value("${elasticsearch.clustername}")
    private String EsClusterName;
    
    @Bean
    public Client esClient() throws UnknownHostException {
        Settings esSettings = Settings.builder()
                .put("cluster.name", EsClusterName)
                .put("client.transport.sniff", true)
                .put("client.transport.ignore_cluster_name", false)
                .build();
    
    
       TransportClient  client = new PreBuiltTransportClient(esSettings)
        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
        return client;
    
    }
    
    @Bean
    public ElasticsearchOperations elasticsearchTemplate() throws Exception{
        return new ElasticsearchTemplate(esClient()); 
      }
    }
    
  2. Apartments.java - This is my data model. The documents have the below fields in elasticsearch.

    @Document(indexName = "house", type = "apartments")
    @JsonIgnoreProperties(ignoreUnknown=true)
    public class Apartments {
    
       @Id
       private String id;
       @JsonProperty("Apartment_Name")
       private String apartmentName;
       @JsonProperty("Apartment_ID")
       private String apartmentId;
       @JsonProperty("Area_Name")
       private String areaName;
    
       //constructors along with getters and setters
    }
    
  3. ApartmentSearchRepository.java - This is an interface that extends the ElasticsearchRepository interface to perform crud operations.

    public interface ApartmentSearchRepository extends ElasticsearchRepository<Apartments, String> {
    List<Apartments> findByApartmentName(String apartmentName);
    }
    
  4. EsApartmentService.java -

    @Service
    public class EsApartmentService {
    
    @Autowired
    ApartmentSearchRepository apartmentSearchRepository;
    
    public List<Apartments> getApartmentByName(String apartmentName) {
        return apartmentSearchRepository.findByApartmentName(apartmentName);
       }
    }
    
  5. ApartmentController.java - I have created an endpoint that should give back those 20 documents from elasticsearch. (Also, Apartment is a POJO in my project and Apartments is the data model.)

    @Autowired
    EsApartmentService esApartmentService;
    @GetMapping(path = "/search",produces = "application/json")
    public Set<Apartment> searchApartmentByName(
      @RequestParam(value = "apartmentName", defaultValue = "") String apartmentName) throws IOException {
      List<Apartment> apartments= new ArrayList<>();
      esApartmentService.getApartmentByName(apartmentName).forEach(apartment-> {
            apartments.add(new Apartment(apartment.getApartmentName(), apartment.getApartmentId(), apartment.getAreaName()));
        });
      return apartments.stream()
              .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Apartment::getApartmentId))));
    }
    

This code gives back a status of 200 but with an empty response. I tried debugging but it seems that it is unable to read those documents from elasticsearch. I went through a couple of solutions but most of them have set the document data from within the code itself.

I am unable to retrieve those documents by hitting the endpoint I specified in the controller. Can someone let me know what I could be missing out on? Thanks! :)

Edit: The screenshot below shows the query and response in Postman. enter image description here

2
Are you able to show us a elasticseach query made via curl or postman? just a match_all query to the _search endpoint of your index. The structure of your document have to match your Apartments.class and we need to verify.ibexit
BTW: You should use the highlevel rest client in your application. The TransportClient will be removed in future version of ES.ibexit
@ibexit Thanks for your reply. I have attached the screenshot of my response in postman. You can verify now.salazarin

2 Answers

2
votes

As far I know, you are able to use @JsonProperty in order to map the POJO to the query response but you're loosing the ability to use the dynamic finder methods (findBy*) of spring data. The dynamic finders generation of spring data relies on reflection and there is where the field names in your POJO become important.

Would you mind to change the field names of you POJO or in your documents to verify this? Or just define a custom query? There is also a powerfull java api where you can define more complex queries: https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.misc.filter

0
votes

As mentioned above by @ibexit, I removed @JsonProperty and used the native search query builder in my service. Also, it was not taking Apartment_Name and worked when I gave apartment_Name. (seems like Elasticsearch has case issues so I gave it in Camel Case.)

My changes:

  1. Apartments.java - Removed @JsonProperty

    @Document(indexName = "house", type = "apartments")
    //@JsonIgnoreProperties(ignoreUnknown=true)
    public class Apartments {
    
     @Id
     private String id;
    
     //@JsonProperty("apartment_ID")
     private String apartment_ID;
    
     //@JsonProperty("Area_Name")
     private String area_Name;
    
     //@JsonProperty("Apartment_Name")
     private String apartment_Name;
    }
    
  2. EsApartmentService.java -

    @Service
    public class EsApartmentService {
    @Autowired
    private  ElasticsearchTemplate elasticsearchTemplate; 
    
    public List<Apartments> getApartmentByName(String apartmentName) {
       SearchQuery searchQuery = new NativeSearchQueryBuilder()           
      .withQuery(org.elasticsearch.index.query.QueryBuilders
        .matchQuery("apartment_Name", apartmentName)).build();
    Page<Apartments> sampleEntities = 
        elasticsearchTemplate.queryForPage(searchQuery,Apartments.class);      
    return sampleEntities.getContent();
      }
    }
    
  3. Removed ApartmentSearchRepository.java file.

These changes gave me the required response! :)