Добавление объектов в массив через Java API

22 views
Skip to first unread message

Дмитрий Белоус

unread,
Apr 29, 2015, 4:53:02 AM4/29/15
to elastics...@googlegroups.com
Добрый день!

Допустим, у нас есть следующий маппинг:

"tweet" : {
  "properties" : {
    "text" : {
      "type" : "string"
    },
    "comments" : {
      "type" : "object",
      "properties" : {
        "text" : {
          "type" : "string"
        },
        "id" : {
          "type" : "long"
        }
      }
    }
  }
}

и в индексе twitter есть документ с этим маппингом:

{
  "text" : "sample text",
  "comments" : []
}

Приведём аналогичные классы в Java:

class Comment {
  String text;
  Long id;
}

class Tweet {
  String text;
  Set<Comment> comments;
}

Теперь вопрос: как добавить очередной объект класса Comment в поле-массив comments? какой способ обновления этого поля является признанным сообществом?
Приведу варианты, рабочие и нет.

1. Рабочий вариант:
Map<String, Object> commentMap = new HashMap<String, Object>();
commentMap.put("id", comment.id);
commentMap.put("text", comment.text);
client.update(new UpdateRequest("twitter", "tweet", "1")
  .script("ctx._source.comments += p")
  .addScriptParam("p", commentMap))
  .actionGet();

3. Не рабочий:
client.update(new UpdateRequest("twitter", "tweet", "1")
  .script("ctx._source.comments += p")
  .addScriptParam("p", toJson(comment)))
  .actionGet();

toJson() - функция, которая любой объект конвертирует в json-строку.

4. Не рабочий:
client.update(new UpdateRequest("twitter", "tweet", "1")
  .script("ctx._source.comments += " + toJson(comment)))
  .actionGet();

5. С помощью рефлексии можно разобрать объект comment, определить его поля и воспользоваться способом 1.

В чём проблема способа 1?
Недостаточный уровень абстракции:
  1. если изменится класс Comment придётся менять метод;
  2. для каждого другого такого класса нужно писать свою реализацию обновления.

Если есть альтернативы способу 5, буду рад их услышать.

Igor Motov

unread,
Apr 29, 2015, 11:37:22 AM4/29/15
to elastics...@googlegroups.com
Когда вы добавляете объект как строку - этот объект становиться строкой с символами { и } внутри и не более. Поэтому надо дать elasticsearch знать, что параметр это объект. Я не знаю как у вас метод toJson работает. Вы XContent в ней используете или какую-нибудь другую  библиотеку? Если XContent, то такие документы можно напрямую добавлять в скрипт, если нет, то можно распарсить JSON еще раз с помощью XContentHelper.convertToMap.

Дмитрий Белоус

unread,
Apr 30, 2015, 4:55:31 AM4/30/15
to elastics...@googlegroups.com
toJson(Object) в моём случае принадлежит классу Gson библиотеки Gson и возвращает строку.
Я решил последовать вашему второму совету и распарсить JSON с помощью XContentHelper.convertToMap,
поскольку не нашёл универсального метода из объекта получить XContent или Map.
Спасибо за помощь!

среда, 29 апреля 2015 г., 18:37:22 UTC+3 пользователь Igor Motov написал:
Reply all
Reply to author
Forward
0 new messages