如何使用spring data elasticSearch映射连接类型

Posted

技术标签:

【中文标题】如何使用spring data elasticSearch映射连接类型【英文标题】:how to mapping join type by using spring data elasticSearch 【发布时间】:2019-04-09 18:36:48 【问题描述】:

我将数据从 es 2.4 重新索引到 5.6。 es 2.4中的数据有2种,2种是父子关系。 重新索引到es 5.6时,索引只包含单一类型,父子关系通过join类型来解析。 上面的数据工作正常。 像这样的映射示例,它包含一个连接类型:

"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 data 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 data 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)

我该如何解决这个问题或正确映射新版本的父子关系?thks!!

【问题讨论】:

你找到方法了吗?我也想知道怎么做 我通过两个索引重新索引它们,因此它将适应未来的版本,一些高级和不成熟的功能建议减少使用 【参考方案1】:

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

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

但是我想不出使用 Spring data 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);

【讨论】:

【参考方案2】:

最后,我放弃了父子关系,我把它们分成了两个独立的索引。如果没有必要,应该少用一些高级功能。

【讨论】:

以上是关于如何使用spring data elasticSearch映射连接类型的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring-data-jpa 获取这些数据如何更正确?

如何在 Spring Boot 应用程序的同一个域类上同时使用 Spring Data JPA 和 Spring Data Elasticsearch 存储库?

如何在 spring-boot 中禁用 spring-data-mongodb 自动配置

如何使用 spring4+spring-data-jpa(hibernateJpaVendorAdapter)+multidatasource+one entityManager+jpaReposit

Spring-data-redis + Lettuce 如何使用 Pipeline

如何使用 Spring Boot 和 Spring Data 访问实体管理器