0
votes

I'm running into a problem with my Elasticsearch Document index creation failing on startup with "java.lang.IllegalArgumentException: can't add a _parent field that points to an already existing type, that isn't already a parent". I'm not sure if this is due to a version upgrade or b/c I am starting with a brand new Elasticsearch server install.

Contrived example that shows what I'm seeing:

// UserSearchResult.java
@Document(indexName = "hr_index", type = "user")
public class UserSearchResult implements Serializable {
    ...
    @Field(type=FieldType.keyword)
    @Parent(type="department")
    private String departmentCode;
    ...
}

// DepartmentSearchResult.java
@Document(indexName = "hr_index", type = "department")
public class DepartmentSearchResult implements Serializable {
    ...
}

When I start my application I get that exception. If I check the ElasticSearch server, I see the "hr_index" index and the "department" mapping, but the "user" mapping is not created.

If I understand the error, it's because "department" is being created and then when Spring tries to create "user" with "department" as its parent, it doesn't like that, since department wasn't previously marked as a parent when it was created.

  1. Is there some way (via annotation?) to denote DepartmentSearchResult as being a parent when it's created somehow?

  2. Or, is it possible to give a hint to Spring Data Elasticsearch as to what order it should create the indices/mappings? I have seen some other posts (Spring Data Elasticsearch Parent/Child Document Repositories / Test execution error) but disabling auto creation and then manually creating it myself (either as part of my Spring codebase or external to the app) seems kind of "un-Spring-y" to me?

  3. Or, is there some other approach I should be taking?

(This is a working Spring application that had been using Spring 4.2.1 and Spring Data Release Train Gosling, that I'm attempting to upgrade to use Spring 5.0.0 and Spring Data Release Train Kay. As part of this I am starting with a fresh Elasticsearch install, and so I'm not sure if this error is coming from the upgrade or just b/c the install is clean).

1
Maybe figured it out - just changed the order of two fields, I had a public class HRService { @Autowired private DepartmentService deptService; @Autowired private UserService userService; } ` and by changing the order so that UserService came first, that fixed it. I'd still be interested if there's a less fragile way of advising Spring the correct order to do things though.Thomas Feiler

1 Answers

1
votes

In the SD ES, issues related to the parent-child relationship at now really poorly developed. The problem is most likely due to the fact that you are using a clean installation of Elasticsearch. Before the update, the problem did not arise, because mappings have already been created. For the solution, you can use elasticsearchTemplate, which is part of SD ES, and ApplicationListener. It's simple. Just 3 steps.

Drop index in ES (it only needs one time):

curl -XDELETE [ES_IP]:9200/hr_index

Tell SD ES not to create indices and mappings automatically

// UserSearchResult.java
@Document(indexName = "hr_index", type = "user", createIndex = false)
public class UserSearchResult implements Serializable {
    ...
    @Field(type=FieldType.keyword)
    @Parent(type="department")
    private String departmentCode;
    ...
}

// DepartmentSearchResult.java
@Document(indexName = "hr_index", type = "department", createIndex = false)
public class DepartmentSearchResult implements Serializable {
    ...
}

Add a ApplicationListener:

@Component
public class ApplicationStartupListener implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //Mapping for child must be created only if mapping for parents doesn't exist
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        elasticsearchTemplate.createIndex(DepartmentSearchResult.class);
        try {
            elasticsearchTemplate.getMapping(DepartmentSearchResult.class);
        } catch (ElasticsearchException e) {
            elasticsearchTemplate.putMapping(UserSearchResult.class);
            elasticsearchTemplate.putMapping(DepartmentSearchResult.class);
        }
    }
}

P.S. Among other things, it is worth paying attention to the fact that with the release of ES 5.6, a process for removing types began. This inevitably entails the removal of the parent-child relationship. In one of the next releases of the SD ES, we will provide the opportunity to work with joins. Working with parent-child relationships is unlikely to be improved