0

My config:

@Configuration
@EnableElasticsearchRepositories(
    basePackages = { "com.aj.new.repositories" })
public class ElasticDataSourceConfig {

    @Bean
    public RestHighLevelClient client() {

        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
            .connectedTo("localhost:9200")
            .build();

        return RestClients.create(clientConfiguration).rest();
    }

    @Bean
    public ElasticsearchRestTemplate elasticsearchTemplate() {
        return new ElasticsearchRestTemplate(client());
    }
}

Document:

@Document(indexName = "provider_search")
public class Provider {

    @Id @Field
    private Long id;

    @Field(type = FieldType.Keyword)
    private String search;

    @Field(name = "ProviderName", type = FieldType.Keyword)
    private String providerName;

    @Field(name = "Address")
    private String address;

    @Field(name = "City")
    private String city;

    @Field(name = "State")
    private String state;

   ...getters...
   ...setters...
}

Usage:

@Service
public class MySearchService {
    
  @Autowired
  private ElasticsearchRestTemplate elasticsearchRestTemplate;

  public List<Provider> searchProvidersUsingElastic(final String 
    providerName, final AddressSearchCriteriaBean addressCriteria) {

    final NativeSearchQueryBuilder searchQueryBuilder = new 
      NativeSearchQueryBuilder();
    
    if (providerName != null) {
      final String regex = ".*" + providerName + ".*";
      searchQueryBuilder.withQuery(regexpQuery("providerName", regex));
    }
    
    if (addressCriteria.getState() != null) {
      searchQueryBuilder.withFilter(matchQuery("state", 
        addressCriteria.getState())
       .fuzziness(Fuzziness.ONE));
    }   
    
    SearchHits<Provider> articles = 
      elasticsearchRestTemplate.search(searchQueryBuilder.build(), 
      Provider.class, IndexCoordinates.of("provider_search"));
    
    final List<Provider> providers = articles
      .stream()
      .map(SearchHit::getContent)
      .collect(Collectors.toList());
    
    return providers;
  }
}

When debugging with or without filters, I get providers with only their ID field populated. Every other field like "search", "state", etc. is null.

This is my first venture in ElasticSearch world and I'm not sure what's wrong here. Any help is appreciated.

Edit:

Provider Mappings from Elasticsearch

{
  "provider_search": {
    "mappings": {
      "properties": {
        "Address": {
          "type": "text",
          "analyzer": "autocomplete"
        },
        "City": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "FaxNumber": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "PhoneNumber": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "ProviderName": {
          "type": "text",
          "analyzer": "autocomplete"
        },
        "State": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "Status": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "Zip": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "fac_dbk": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "id": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "search": {
          "type": "text",
          "analyzer": "autocomplete"
        }
      }
    }
  }
}

Please note that for testing purposes, I have not mapped every field of Provider on Java side. If that's problematic, let me know.

Second Update:

I have changed the Provider document to map the Field names as is. Still, everything except id is still null.

@Document(indexName = "provider_search")
    public class Provider {
    
        @Id
        private Long id;
    
        private String search;
    
        private String ProviderName;
    
        private String Address;
    
        private String City;
    
        private String State;
    
       ...getters...
       ...setters...
    }

UPDATE:

Turns out the Elasticsearch index had a bug and the fields I had mapped on the Java side were not available on the ES index. It has been fixed and I'm seeing all the values populate correctly.

Anjil Dhamala
  • 1,544
  • 3
  • 18
  • 37
  • your service class example is not compilable. what does Elasticsearch return when you query http://localhost:9200/provider_search/_doc/ID with one of the returned IDs? – P.J.Meisch Jan 08 '21 at 22:16
  • By incompatible, did you mean I was missing method signature and some variable definition? If you were, I have rectified that. And, navigating to the URL with a returned ID gives me back a JSON of a Provider Document with all the fields populated as expected. No nulls. – Anjil Dhamala Jan 08 '21 at 22:56
  • I don't see getContent in official client https://github.com/elastic/elasticsearch/blob/master/server/src/main/java/org/elasticsearch/search/SearchHit.java which library are you using ? – Developer Jan 09 '21 at 06:52
  • I'm using spring-data-elasticsearch: 4.0.5.RELEASE – Anjil Dhamala Jan 09 '21 at 13:28
  • I did not write "incompatible", but not compilable; I see that now the code is edited. @Developer: this is the `SearchHit` from Spring Data Elasticsearch, not from Elasticsearch. – P.J.Meisch Jan 09 '21 at 18:54

1 Answers1

0

You have an inconsistency in using the property names (the properties of the Provider entity) and the corresponding field names (the names in Elasticsearch).

Your properties start with a lowercase letter and then are camelcase (providerName, state), for Spring Data Elasticsearch you define them to map to versions starting with a uppercase letter (ProviderName, State) with the @Field annotations. So Spring Data Elasticsearch expects Elasticsearch to return a value for ProviderName and will then store this in the providerName property.

Are the field names in your index starting with an uppercase letter? What does http://localhost:9200/provider_search/_mappings show? This is a guess, as you did not show what Elasticsearch returns, but would explain your error.

P.J.Meisch
  • 18,013
  • 6
  • 50
  • 66
  • Thanks for taking your time to write the answer. I was assuming the "name" property of Field annotation is what represents the actual name of the field in Elasticsearch and the camelCase name is what I've assigned it in the Spring application. Regardless, after I posted the question, I rewrote the entire Provider document with as is field names from Elasticsearch. That didn't make a difference. Everything except id were still null. I've also updated my question. – Anjil Dhamala Jan 09 '21 at 22:01
  • You still do not show the actual answer when retrieving a document directly from Elasticsearch. – P.J.Meisch Jan 09 '21 at 22:32
  • Apologies for getting back late. Turns out the Elasticsearch index had a bug and the fields I had mapped on the Java side were not available on the ES index. – Anjil Dhamala Jan 11 '21 at 20:59