问题
I am implementing a spring-boot microservice for elasticsearch (es) operations using springdata APIs. My documents that are indexed in es are huge with multiple fields (more than 100).
Is there a way to avoid defining/hardcoding all the fields in the entity class for elasticsearch object in java?
My sample patient JSON could be like:
{
"key_1":"value_1",
"key_2":"value_2",
"key_3":"value_3",
.
.
.
"key_n":"value_n"
}
回答1:
If you can go for a slightly different form to store your data in Elastcisearch, you can go use the following:
Define your entity as follows (I am omitting getter/setter for brevity):
@Document(indexName = "innerdata")
public class InnerDataEntity {
@Id
private String id;
@Field(type = FieldType.Object)
private List<InnerData> innerData;
static class InnerData {
@Field(type = FieldType.Text)
private String key;
private String value;
}
}
Using this with a Spring Data Elasticsearch Repository will create the index with the following mappings:
{
"innerdata": {
"mappings": {
"properties": {
"id": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"innerData": {
"properties": {
"key": {
"type": "text"
}
}
}
}
}
}
}
The value
property is automapped, if you need to search them as well, add the FieldType.Text
.
You can then search with the key value by defining a repository like this:
public interface InnerDataRepository extends ElasticsearchRepository<InnerDataEntity, String> {
SearchHits<InnerDataEntity> searchByInnerData_Key(String key);
}
and use it for example in a controller:
@GetMapping("/{key}")
public SearchHits<InnerDataEntity> allByKey(@PathVariable String key) {
return repository.searchByInnerData_Key(key);
}
The data that is stored in Elasticsearch looks like this:
{
"hits": {
"hits": [
{
"_id": "1",
"_index": "innerdata",
"_score": 1.0,
"_source": {
"id": "1",
"innerData": [
{
"key": "key-1",
"value": "value-1"
},
{
"key": "key-2",
"value": "value-2"
}
]
},
"_type": "_doc"
},
{
"_id": "2",
"_index": "innerdata",
"_score": 1.0,
"_source": {
"id": "2",
"innerData": [
{
"key": "key-1",
"value": "value-1"
},
{
"key": "key-3",
"value": "value-3"
}
]
},
"_type": "_doc"
}
]
}
}
}
回答2:
Thank you "@P.J.Meisch", for pointing me the right direction!
I resolved the issue by performing document (json) restructuring, that will be indexed in elasticsearch. It was done by keeping the anonymised patient id at the root level and rest of the patient details in a sub json. Below is my Model class.
@Component
@Document(indexName = "manual_patients") // name must be lower case
@Getter
@Setter
@ToString(callSuper=true, includeFieldNames=true)
// @NoArgsConstructor
public class ManualPatient {
@Id
private String _id = UUID.randomUUID().toString();
@ApiModelProperty(position = 0)
private String patientId;
private Map patientDetails;
public ManualPatient(){}
public ManualPatient( String patientId, Map patientDetails) {
this.patientId = patientId;
this.patientDetails = patientDetails;
}
}
来源:https://stackoverflow.com/questions/63780364/can-we-avoid-mapping-all-the-fields-to-entity-class-in-springdata-for-elasticsea