Mola elástica : Qual é a maneira correta de usar campos aninhados?

0

Pergunta

Eu sou muito novo para ElasticSearch. Eu estou trabalhando em um projeto onde precisamos procurar um objeto (Oferta) que contém um Conjunto de dois (OfferTranslation). O objetivo é fazer a pesquisa, com base em algumas de Oferta de campos, mas também um monte de OfferTranslation campos. Aqui está uma só versão de ambas as turmas :

Offer.class (note que eu anotada com @Campo(tipo= FieldType.Aninhado) para que eu possa fazer consultas Aninhadas, como mencionado no diário oficial doc) :

@org.springframework.data.elasticsearch.annotations.Document(indexName = "offer")
@DynamicMapping(DynamicMappingValue.False)
public class Offer implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @Field(type = FieldType.Long)
    private Long id;

    @OneToMany(mappedBy = "offer", targetEntity = OfferTranslation.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    @JsonIgnoreProperties(
        value = { "pictures", "videos", "owner", "contexts", "offer", "personOfInterests", "followers" },
        allowSetters = true
    )
    @Field(type = FieldType.Nested, store = true)
    private Set<OfferTranslation> offersTranslations = new HashSet<>();


}

OfferTranslation.class :

@DynamicMapping(DynamicMappingValue.False)
public class OfferTranslation implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @Field(type = FieldType.Long)
    private Long id;

    @NotNull
    @Size(max = 100)
    @Column(name = "title", length = 100, nullable = false)
    @Field(type = FieldType.Text)
    private String title;

    @NotNull
    @Size(max = 2000)
    @Column(name = "summary", length = 2000, nullable = false)
    @Field(type = FieldType.Text)
    private String summary;

    @Size(max = 2000)
    @Column(name = "competitor_context", length = 2000)
    @Field(type = FieldType.Text)
    private String competitorContext;

    @NotNull
    @Size(max = 2000)
    @Column(name = "description", length = 2000, nullable = false)
    @Field(type = FieldType.Text)
    private String description;

    @NotNull
    @Enumerated(EnumType.STRING)
    @Column(name = "maturity", nullable = false)
    @Field(type = FieldType.Auto)
    private RefMaturity maturity;

    @ManyToOne
    @Field(type = FieldType.Object, store = true)
    private RefLanguage language;

    @NotNull
    @Column(name = "created_at", nullable = false)
    @Field(type = FieldType.Date)
    private Instant createdAt;
}

O comportamento esperado seria que eu posso fazer nestedQueries assim :

QueryBuilder qBuilder = nestedQuery("offersTranslations",boolQuery().must(termQuery("offersTranslations.language.code",language)), ScoreMode.None);

Mas o que eu vejo é uma exceção : falha ao criar consulta: [aninhadas] objeto aninhado em caminho [offersTranslations] não é do tipo aninhado"

EDIT : eu posso acessar offersTranslations.idioma.o código usando consultas normais (que realmente não me incomoda no momento). Mas eu ainda não entendo realmente.

Minha mapeamento diz que o campo offersTranslations não é de um tipo aninhado como você pode ver acima, mas desde que eu usei @Campo(tipo = FieldType.Aninhado) eu realmente não entendo esse comportamento. Alguém poderia explicar?

{
  "offer" : {
    "mappings" : {
      "properties" : {
        "_class" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "categories" : {
          "properties" : {
            "id" : {
              "type" : "long"
            }
          }
        },
        "criteria" : {
          "properties" : {
            "id" : {
              "type" : "long"
            }
          }
        },
        "id" : {
          "type" : "long"
        },
        "keywords" : {
          "properties" : {
            "id" : {
              "type" : "long"
            }
          }
        },
        "offersTranslations" : {
          "properties" : {
            "competitorContext" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "createdAt" : {
              "type" : "date"
            },
            "description" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "id" : {
              "type" : "long"
            },
            "language" : {
              "properties" : {
                "code" : {
                  "type" : "text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                },
                "id" : {
                  "type" : "long"
                },
                "name" : {
                  "type" : "text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                }
              }
            },
            "maturity" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "state" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "summary" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "title" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "updatedAt" : {
              "type" : "date"
            }
          }
        },
        "units" : {
          "properties" : {
            "id" : {
              "type" : "long"
            }
          }
        }
      }
    }
  }
}
2

Melhor resposta

1

Como foi o índice de mapeamento criado? Ela não se parece com a Primavera de Dados Elasticsearch escreveu esse mapeamento. Aninhado tipo de offerTranslations está em falta, como você viu, e os campos de texto têm um .keyword subcampo. Isto parece dados foi inserida no índice sem ter um mapeamento definido e assim Elasticsearch fez um mapeamento automático. Neste caso, os valores de @Field as anotações não são usados.

Você precisa ter a Primavera de Dados Elasticsearch criar o índice com o mapeamento. Isto acontece automaticamente, se o índice não existe e você estiver usando o Spring Data Elasticsearch repositórios, ou você precisa usar o IndexOperations.createWithMapping função em seu aplicativo.

Outra coisa que eu observei: - parece que você está usando a mesma entidade de classe para diferentes Primavera armazenamentos de Dados, a mistura fortemente as anotações. Você deve usar diferentes entidades para diferentes lojas.

2021-11-22 17:12:04

Eu tentei apagar o mapeamento usando kibana : EXCLUIR oferta/_mapping e a reindexação minhas ofertas. Mas talvez usando um explícito "createWithMapping" pode funcionar melhor, eu vou deixar você saber se isso ajuda ! Obrigado de qualquer maneira
Aymane EL Jahrani

Olá, então eu tentei usar o createWithMapping, mas não parece ser simples. Você pode confirmar que essa é a maneira correta de usá-lo ? github.com/spring-projects/spring-data-elasticsearch/blob/main/...
Aymane EL Jahrani
0

PASSOS PARA RESOLVER :

  • Use Kibana para certificar-se de que você EXCLUA <index_name>/_mapping
  • Procure na sua entidade de classes de objetos que você precisa que pode estar em um @JsonIgnoreProperties
  • Certifique-se de que você ANSIOSAMENTE carregar seu para muitos da relação de atributos (caso contrário elástico não criar um mapeamento para um dados que você nunca deu)
  • Esta pequena experiência, eu diria que evitar o uso de campos Aninhados, eu não podia ver qualquer vantagem de usá-los. Portanto, verifique se for o caso para você também !
2021-11-25 23:17:34

Primavera de Dados Elasticsearch dos não fazer nada com o @JsonIgnoreProperties anotação. Elasticsearch não é de banco de dados relacional e não tem nenhuma noção de relacionamentos entre entidades.
P.J.Meisch

Isso é verdade, mas a primavera faz isso quando serialising de dados. É assim que eu obter o meu entidades ...
Aymane EL Jahrani

Primavera em si não faz isso. Spring Data JPA faz, por exemplo. Primavera de Dados Elasticsearch não fazê-lo. Estes são os diferentes Primavera módulos de Dados.
P.J.Meisch

A biblioteca fasterxml.jackson faz isso ,e ele funciona usando anotações JPA/Hibernate entidades. Isso é o que eu uso neste projeto, como você pode ver no meu código...
Aymane EL Jahrani

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................