Additionner dans un script


(Christophe Boucaut) #1

Bonjour,

Je suis en train de me casser les dents pour écrire un script dans le but de réaliser un sort. J'ai deux champs dans mon document. Si le premier est vide, je prends simplement la valeur du second. Par contre, si le premier existe et est rempli, je souhaite parcourir le tableau d'objets et additionner les différentes valeurs d'une propriété de chaque objets.

Mon problème : Malgré le fait que dans mon mapping, le champs soit renseigné comme "integer", java me ressort un problème de cast d'une String vers un Number (d'après le message d'erreur récupéré).

Mon mapping :

[...]
"element_nb": {
    "properties": {
         "element_name": { "type": "string", "index": "no" },
         "nb": { "type": "integer"}
     }
}
"nb_documents": { "type": "integer"},
[...]

Ma query :

{
  "sort": [
    {
      "_script": {
        "order": "desc",
        "type": "number",
        "script": "
            score_count = 0;
            if (_source.element_nb != null && _source.element_nb.size() > 0) {
                for (item in _source.element_nb) {
                    if (item.nb != null) {
                        score_count += item.nb;
                    }
                }
            } else {
                score_count = doc.nb_documents.value;
            };
            score_count;
            "
      }
    }
  ]
}

J'utilise _source car de toute évidence, vu que mon champs element_name n'est pas indexé, le champs parent element_name n'est pas dans doc. J'ai mis le script en forme pour être plus lisible, mais je l'envoie bien en inline.

L'erreur récupérée :

Query Failed [Failed to execute main query]]; nested:
GroovyScriptExecutionException[MissingMethodException[
    No signature of method: java.lang.Integer.plus() is applicable for argument types: ([C) values: [17]
    Possible solutions: plus(java.lang.Character), plus(java.lang.String), plus(java.lang.Number), abs(), split(groovy.lang.Closure), is(java.lang.Object)]];}]

Donc par exemple pour un document du type :

{
    nb_documents: 5
}

La valeur du sort sera simplement 5.

Dans le cas d'un document du type :

{
    element_nb: [
        {element_name: 'une_valeur', nb: 100},
        {element_name: 'une_valeur', nb: 200}
    ],
    nb_documents: 5
}

La valeur du sort devrait être 300 (100 + 200).

Je suis en ES 1.7.

Merci par avance si vous pouvez m'aiguiller sur une solution :slight_smile:


(Christophe Boucaut) #2

J'ai identifié mon soucis. J'appelle _source. En regardant ce que j'envoie réellement, j'ai remarqué que j'envoie

{
    "element_nb": [
        {"element_name": "une_valeur", "nb": "100"},
        {"element_name": "une_valeur", "nb": "200"}
    ],
   "nb_documents": 5
}

Donc forcément, ma valeur est une string. Du coup, si je passe par doc.element_nb.nb mon problème devrait être réglé. Cependant, ES ne connait jamais mon champ element_nb dans doc. J'ai modifié le mapping pour indexer tous les champs enfants, mais rien n'y fait. J'ai essayé sur d'autres champs qui contiennent eux même des tableaux d'objets et j'ai le même soucis, ils sont inaccessibles depuis le doc.

Je vais chercher comment les rendre accessible depuis le doc. Si vous avez des pistes, j'accepte volontiers :wink:


(Christophe Boucaut) #3

Encore moi.... j'ai finalement trouvé.

Il suffit de faire doc['element_nb.nb']. Merci à sense pour l'auto-complete qui sauve !

EDIT : Il reste tout de même un problème ... Boucler dessus fonctionne mais il y a un distinct réalisé. Du coup, si j'ai deux objets avec la même valeur pour nb, il n'additionnera pas ... Je ne suis même pas sur que l'on puisse itérer sur un objet du doc sans qu'il réalise un distinct dessus :frowning:


(system) #4