Search code examples
springspring-dataspring-data-elasticsearch

Spring Data Elasticsearch Inheritance


Is there any way to make a super-class document (e.g. index name = user) and create two child classes (Admin, Guest) to save all this to user index but with different fields? E.g. Add to super-class field type and based on this field fetch right entity? ELK 7.19, Spring Data 4.3.1.


Solution

  • You can do that. Make the base class abstract. I have this in a test setup with the following classes:

    @Document(indexName = "type-hints")
    public abstract class BaseClass {
    
        @Id
        private String id;
    
        @Field(type = FieldType.Text)
        private String baseText;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getBaseText() {
            return baseText;
        }
    
        public void setBaseText(String baseText) {
            this.baseText = baseText;
        }
    
        @Override
        public String toString() {
            return "BaseClass{" +
                "id='" + id + '\'' +
                ", baseText='" + baseText + '\'' +
                '}';
        }
    }
    
    public class DerivedOne extends BaseClass {
        @Field(type = FieldType.Text)
        private String derivedOne;
    
        public String getDerivedOne() {
            return derivedOne;
        }
    
        public void setDerivedOne(String derivedOne) {
            this.derivedOne = derivedOne;
        }
    
        @Override
        public String toString() {
            return "DerivedOne{" +
                "derivedOne='" + derivedOne + '\'' +
                "} " + super.toString();
        }
    }
    
    public class DerivedTwo extends BaseClass {
        @Field(type = FieldType.Text)
        private String derivedTwo;
    
        public String getDerivedTwo() {
            return derivedTwo;
        }
    
        public void setDerivedTwo(String derivedTwo) {
            this.derivedTwo = derivedTwo;
        }
    
        @Override
        public String toString() {
            return "DerivedTwo{" +
                    "derivedTwo='" + derivedTwo + '\'' +
                    "} " + super.toString();
        }
    }
    
    interface TypeHintRepository extends ElasticsearchRepository<BaseClass, String> {
        SearchHits<? extends BaseClass> searchAllBy();
    }
    
    @RestController
    @RequestMapping("/typehints")
    public class TypeHintController {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(TypeHintController.class);
    
        private final TypeHintRepository repository;
    
        public TypeHintController(TypeHintRepository repository) {
            this.repository = repository;
        }
    
        @GetMapping
        public void test() {
    
            List<BaseClass> docs = new ArrayList<>();
    
            DerivedOne docOne = new DerivedOne();
            docOne.setId("one");
            docOne.setBaseText("baseOne");
            docOne.setDerivedOne("derivedOne");
            docs.add(docOne);
    
            DerivedTwo docTwo = new DerivedTwo();
            docTwo.setId("two");
            docTwo.setBaseText("baseTwo");
            docTwo.setDerivedTwo("derivedTwo");
            docs.add(docTwo);
    
            repository.saveAll(docs);
    
            SearchHits<? extends BaseClass> searchHits = repository.searchAllBy();
    
            for (SearchHit<? extends BaseClass> searchHit : searchHits) {
                LOGGER.info(searchHit.toString());
            }
        }
    }