Printemps élastique : Quelle est la bonne façon d'utiliser des champs imbriqués?

0

La question

Je suis assez nouveau dans ElasticSearch. Je travaille sur un projet où nous avons besoin de rechercher un objet (l'Offre) qui contient un Ensemble de deux (OfferTranslation). L'objectif est de faire de la recherche basée sur certaines Offrent des champs, mais aussi beaucoup de OfferTranslation champs. Voici une version compacte de deux classes :

Offer.class (notez que j'ai annotée avec @Domaine(type= type de champs.Imbriquée) donc je peux faire des requêtes Imbriquées, comme mentionné dans la doc officielle) :

@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;
}

Le comportement attendu est que je peut faire nestedQueries de la manière suivante :

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

Mais ce que j'ai est une exception : impossible de créer la requête: [imbriquée] objet imbriqué dans chemin d'accès [offersTranslations] n'est pas de type imbriqué"

EDIT : je peux accéder à offersTranslations.de langue.le code à l'aide des requêtes normales (qui n'a pas vraiment me dérange pas pour le moment). Mais je n'ai pas encore vraiment comprendre.

Ma cartographie dit le champ offersTranslations n'est pas d'un type imbriqué comme vous pouvez le voir ci-dessus, mais depuis que j'ai utilisé @Domaine(type = type de champs.Imbriquée) je ne comprends pas vraiment ce comportement. Quelqu'un pourrait-il m'expliquer?

{
  "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

La meilleure réponse

1

Comment était l'indice de la cartographie créé? Il ne ressemble pas du Ressort des Données Elasticsearch a écrit cette cartographie. Le sous-type de offerTranslations est manquante comme vous l'avez vu et les champs de texte ont une .keyword sous-champ. Cela ressemble à des données ont été insérées dans l'index sans avoir un mappage défini et donc Elasticsearch a fait une cartographie automatique. Dans ce cas, les valeurs de la @Field les annotations ne sont pas utilisés.

Vous avez besoin d'avoir le Printemps de Données Elasticsearch créer l'index de la correspondance. Cela se fera automatiquement si l'index n'existe pas et vous êtes à l'aide de Données du Printemps Elasticsearch référentiels, ou vous avez besoin d'utiliser la IndexOperations.createWithMapping fonction dans votre application.

Une autre chose que j'ai remarqué: il semble que vous êtes à l'aide de la même classe d'entité pour les différentes Printemps magasins de Données, le mélange fortement les annotations. Vous devez utiliser des entités différentes pour les différents magasins.

2021-11-22 17:12:04

J'ai essayé de la suppression de la cartographie à l'aide de kibana : SUPPRIMER offre/_mapping et réindexation de mon offre. Mais peut-être l'aide d'un explicite "createWithMapping" pourrait fonctionner mieux, je vais vous laisser savoir si cela aide ! Merci en tout cas
Aymane EL Jahrani

Bonjour, j'ai donc essayé d'utiliser le createWithMapping, mais il ne semble pas être simple. Pouvez-vous confirmer que c'est la bonne façon de l'utiliser ? github.com/spring-projects/spring-data-elasticsearch/blob/main/...
Aymane EL Jahrani
0

DES MESURES POUR LE RÉSOUDRE :

  • Utilisation Kibana pour assurez-vous de SUPPRIMER <index_name>/_mapping
  • Regardez dans vos classes d'entités pour les objets dont vous avez besoin qui peut être dans un @JsonIgnoreProperties
  • Assurez-vous que vous avec IMPATIENCE la charge de votre relation à plusieurs attributs (sinon élastique de ne pas créer un mappage de données vous n'avez jamais donné)
  • À partir de ce peu d'expérience, je dirais d'éviter d'utiliser des champs Imbriqués, je ne vois aucun avantage de leur utilisation. Afin de vérifier si c'est le cas pour vous aussi !
2021-11-25 23:17:34

Printemps de Données Elasticsearch dos pas faire n'importe quoi avec l' @JsonIgnoreProperties annotation. Elasticsearch est pas de base de données relationnelle et n'a aucune notion de relations entre les entités.
P.J.Meisch

C'est vrai, mais le printemps n'est que lorsque serialising de données. C'est la façon d'obtenir mon entités ...
Aymane EL Jahrani

Le printemps lui-même ne le fait pas. Spring Data JPA n'est que par exemple. Printemps de Données Elasticsearch ne pas le faire. Ceux-ci sont différents de Printemps, les modules de Données.
P.J.Meisch

La bibliothèque fasterxml.jackson fait ça ,et il fonctionne en utilisant des annotations JPA/Hibernate entités. C'est ce que j'utilise dans ce projet, comme vous pouvez le voir dans mon code...
Aymane EL Jahrani

Dans d'autres langues

Cette page est dans d'autres langues

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