Resorte elástico: ¿Cuál es la forma correcta de utilizar campos anidados?

0

Pregunta

Soy bastante nuevo en ElasticSearch. Estoy trabajando en un proyecto donde tenemos que buscar un objeto (Oferta) que contiene un Conjunto de dos (OfferTranslation). El objetivo es hacer de la investigación basada en algunos de Ofrecer a los campos, sino también un montón de OfferTranslation campos. He aquí un record de la versión de dos clases :

Offer.class (tenga en cuenta que he anotado el Conjunto con @Field(type= FieldType.Anidada) para que yo pueda hacer consultas Anidadas, tal y como figura en el boletín 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;
}

El comportamiento esperado sería que puedo hacer nestedQueries así como :

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

Pero lo que me pasa es una excepción : no se pudo crear la consulta: [anidada] objeto anidado en ruta de acceso [offersTranslations] no es de tipo anidado"

EDIT : puedo acceder a offersTranslations.lenguaje.código mediante consultas normales (que realmente no me molesta en el momento). Pero yo todavía no entiendo muy bien.

Mi asignación dice que el campo offersTranslations no es de un tipo anidado como se puede ver arriba, pero ya que yo solía @Field(type = FieldType.Anidada) realmente no entiendo ese comportamiento. Podría alguien 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

Mejor respuesta

1

¿Cómo fue el índice de asignación creado? No se ve como la Primavera de Datos Elasticsearch escribió esta asignación. El tipo anidado de offerTranslations falta como lo vio y de los campos de texto tienen una .keyword subcampo. Esto se parece a los datos se insertan en el índice sin tener una asignación definida y por lo Elasticsearch hizo un mapeo automático. En este caso, los valores de la @Field las anotaciones no se utiliza.

Usted necesita tener la Primavera de Datos Elasticsearch crear el índice, con la asignación. Esto sucederá automáticamente si el índice no existe y usted está utilizando la Primavera de Datos Elasticsearch repositorios, o usted necesita utilizar el IndexOperations.createWithMapping función en su aplicación.

Otra cosa que he notado: parece que usted está usando la misma clase de entidad para la Primavera diferentes almacenes de Datos, la mezcla fuertemente las anotaciones. Se deben utilizar diferentes entidades para las diferentes tiendas.

2021-11-22 17:12:04

He intentado eliminar el mapeo de uso de la kibana : ELIMINAR oferta/_mapping y a indexar mis ofertas. Pero tal vez el uso de un explícito "createWithMapping" podría funcionar mejor, voy a dejar que usted sabe si esto ayuda ! Gracias de todos modos
Aymane EL Jahrani

Hola, lo he intentado usando el createWithMapping, pero no parece ser sencilla. Usted puede confirmar que esta es la manera correcta de usarlo ? github.com/spring-projects/spring-data-elasticsearch/blob/main/...
Aymane EL Jahrani
0

PASOS PARA SOLUCIONARLO :

  • Uso Kibana para asegurarse de que usted ELIMINE <index_name>/_mapping
  • Buscar en las clases de entidad de objetos que pueden encontrarse en un @JsonIgnoreProperties
  • Asegúrese de que usted ANSIOSAMENTE la carga de su relación de muchos de los atributos (de lo contrario elástica no crear una asignación de datos que nunca se dio)
  • A partir de esta pequeña experiencia, yo diría que evitar el uso de campos Anidados, yo no podía ver ninguna ventaja de la utilización de ellos. A fin de comprobar si ese es el caso para usted también !
2021-11-25 23:17:34

La primavera de Datos Elasticsearch dos no hacer nada con el @JsonIgnoreProperties la anotación. Elasticsearch es ninguna base de datos relacional y no tiene noción de las relaciones entre las entidades.
P.J.Meisch

Eso es cierto, pero la primavera hace que cuando serialising de datos. Que cómo puedo obtener mi entidades ...
Aymane EL Jahrani

La primavera de sí mismo no lo hace. Spring Data JPA hace que por ejemplo. La primavera de Datos Elasticsearch no hacerlo. Estos son diferentes de la Primavera de los módulos de Datos.
P.J.Meisch

La biblioteca fasterxml.jackson hace eso ,y funciona mediante anotaciones de JPA/Hibernate entidades. Eso es lo que yo uso en este proyecto como se puede ver en mi código...
Aymane EL Jahrani

En otros idiomas

Esta página está en otros idiomas

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