如何通过使用Spring数据elasticSearch映射联接类型

时间:2018-11-06 11:11:24

标签: elasticsearch spring-data-elasticsearch

i将数据从es 2.4重新索引到5.6。
es 2.4中的数据有2种类型,其中2种是父子关系。
将其重新索引到es 5.6时,索引仅包含单个类型,通过使用连接类型进行解析来建立父子关系。
上面的数据正常。 像这样的映射示例,它包含一个联接类型:

"mappings": {
    "doc": {
        "properties": {
            "my_join_field": {
                "eager_global_ordinals": true,
                "type": "join",
                "relations": {
                    "question": "answer"
                }
            },
            "name": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "ignore_above": 256,
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

如何通过使用spring数据elasticSearch映射联接类型: 在旧版本代码es 2.4中,我可以这样映射它:

@Document(indexName = ParentEntity.INDEX, type = ParentEntity.PARENT_TYPE, shards = 1, replicas = 0, refreshInterval = "-1")
public class ParentEntity {

    public static final String INDEX = "parent-child";
    public static final String PARENT_TYPE = "parent-entity";
    public static final String CHILD_TYPE = "child-entity";

    @Id
    private String id;
    @Field(type = FieldType.Text, store = true)
    private String name;

    public ParentEntity() {
    }

    public ParentEntity(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return new ToStringCreator(this).append("id", id).append("name", name).toString();
    }

    @Document(indexName = INDEX, type = CHILD_TYPE, shards = 1, replicas = 0, refreshInterval = "-1")
    public static class ChildEntity {

        @Id
        private String id;
        @Field(type = FieldType.Text, store = true)
        @Parent(type = PARENT_TYPE)
        private String parentId;
        @Field(type = FieldType.Text, store = true)
        private String name;

        public ChildEntity() {
        }

        public ChildEntity(String id, String parentId, String name) {
            this.id = id;
            this.parentId = parentId;
            this.name = name;
        }

        public String getId() {
            return id;
        }

        public String getParentId() {
            return parentId;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return new ToStringCreator(this).append("id", id).append("parentId", parentId).append("name", name).toString();
        }
    }
}

如何使用Spring Data ElasticSearch v3.0.10映射联接类型?

今天,我尝试使用以下实体在spring数据elasticSearch 3.0.10中工作:

@Document(indexName = "join_index", type = "join_mapping")
@Data
public class JoinEntity {
    @Id
    private String id;
    @Mapping(mappingPath = "/mappings/join_type.json")
    private Map<String,String> relationType;
    @Field(type = FieldType.Keyword)
    private String name;
    //@Parent(type = "question")
    @Field(type = FieldType.Keyword)
    private String parentId;
}

join_type.json如下:

{
  "type": "join",
  "relations": {
    "question": "answer"
  }
}

它创建索引并使映射工作正常:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
public class ElasticsearchTemplateJoinTests {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Before
    public void before() {
        clean();
        elasticsearchTemplate.deleteIndex(JoinEntity.class);
        elasticsearchTemplate.createIndex(JoinEntity.class);
        elasticsearchTemplate.putMapping(JoinEntity.class);
        elasticsearchTemplate.refresh(JoinEntity.class);
    }

    @Test
    public void shouldCreateIndexAndMappingSuccess(){
        Map mapping = elasticsearchTemplate.getMapping(JoinEntity.class);
        assertThat(mapping, is(notNullValue()));

        Map properties = (Map) mapping.get("properties");
        assertThat(properties, is(notNullValue()));

        assertThat(properties.containsKey("name"), is(true));
        Map file = (Map) properties.get("relationType");
        assertThat(file, is(notNullValue()));
        assertThat(((String) file.get("type")), is("join"));
    }
}

当索引父级也可以工作但索引子级也抛出异常时:

@Test 
public void shouldIndexParentAndChildSuccess(){
    JoinEntity parenEntity = new JoinEntity();
    parenEntity.setName("parent_name");
    parenEntity.setRelationType(Collections.singletonMap("name","question"));
    IndexQuery parentQuery = new IndexQueryBuilder().withId("11").withObject(parenEntity).build();
    final String id = elasticsearchTemplate.index(parentQuery);
    assertThat("11",is(id));
    JoinEntity childEntity = new JoinEntity();
    childEntity.setName("child_name");
    Map<String,String> joinRelation = new HashMap<>(2);
    joinRelation.put("name","answer");
    joinRelation.put("parent", "11");
    childEntity.setRelationType(joinRelation);
    childEntity.setParentId("11");
    IndexQuery childQuery = new IndexQueryBuilder().withId("22").withObject(childEntity).build();
    elasticsearchTemplate.index(childQuery);
}

例外:

MapperParsingException[failed to parse
]; nested: IllegalArgumentException[[routing] is missing for join field [relationType]];
    at org.elasticsearch.index.mapper.DocumentParser.wrapInMapperParsingException(DocumentParser.java:171)

我该如何解决此问题或正确映射新版本的亲子关系呢?

2 个答案:

答案 0 :(得分:0)

在索引子文档check this时,Elasticsearch需要父文档路由参数

这是因为父文档和子文档都必须在相同的分片中建立索引才能加入工作。

但是我找不到使用Spring数据Elasticsearch解决此问题的方法。唯一有效的方法是使用 RestHighLevelClient

Spring Data ElasticSearch的最新版本已添加对此doc

的支持

您的子索引将类似于

    IndexRequest indexRequest = new IndexRequest();
    indexRequest.source(objectMapper.writeValueAsString(childEntity),XContentType.JSON);
    indexRequest.id("22"); //child doc id
    indexRequest.index(INDEX_NAME);
    indexRequest.type(INDEX_TYPE);
    indexRequest.routing("11"); //parent doc id
    restHighLevelClient.index(indexRequest);

答案 1 :(得分:0)

最后,我放弃了父子关系,将它们分为两个单独的索引。某些高级功能应尽量减少使用。