Серия Timelion из кумулятивной суммы длины массива

У меня есть документы, которые выглядят примерно так:

{
    dateTime: /* My time field */,
    message: {
        users: ['1', '2']
    },
    messageType: 'test'
}

Я хотел бы построить диаграмму серии timelion, которая показывает мне кумулятивную сумму количества массива message.users. Моей первой мыслью было создать скрипт:

if(doc.containsKey('message.users')) {
    return doc['message.users'].length;
} else {
    return 0;
}

Из того, что я мог сказать, doc.containsKey('message.users') всегда было ложным, что говорит мне о том, что он, возможно, был неправильно проиндексирован. Я пробовал множество Timelion, все безрезультатно:

.es(index=logstash-*,timefield='dateTime',q='messageType:UserList').label('Users Online')

Я индексирую свой документ через С# NEST API следующим образом:

elasticClient.Index(
    new
    {
        DateTime = DateTime.Now,
        Message = evt.EventArgs.Message,
    },
    idx => idx.Index($"logstash-{evt.MessageCode}"));

person Goodbye StackExchange    schedule 25.07.2017    source источник
comment
Можете ли вы поделиться сопоставлением вашего поля message.users?   -  person Val    schedule 27.07.2017
comment
Еще одна хорошая практика — просто создать еще одно поле во время индексации с именем userCount, которое содержит количество пользователей в вашем массиве message.users.   -  person Val    schedule 27.07.2017
comment
@Val, извините, новичок в elasticsearch. Я только что использовал C # Nest API и обновил свой ответ, указав, как я индексирую документ.   -  person Goodbye StackExchange    schedule 27.07.2017


Ответы (1)


Я предлагаю добавить еще одно поле с именем userCount в ваши документы, чтобы вам не нужно было возиться со скриптами (+ это будет более производительно).

Итак, ваши документы должны выглядеть так:

{
    dateTime: /* My time field */,
    message: {
        users: ['1', '2']
    },
    userCount: 2,                  <--- add this field
    messageType: 'test'
}

Решение 1:

Вам нужно немного изменить свой код на это:

elasticClient.Index(
    new
    {
        DateTime = DateTime.Now,
        Message = evt.EventArgs.Message,
        UserCount = evt.EventArgs.Message.Users.Length
    },
    idx => idx.Index($"logstash-{evt.MessageCode}"));

Решение 2:

Если вы используете ES 5, вы можете использовать Ingest API. чтобы создать конвейер, который автоматически добавит это поле userCount для вас. Вам не нужно ничего менять в своем коде.

PUT _ingest/pipeline/user-count-pipeline
{
  "description" : "Creates a new userCount field",
  "processors" : [
    {
      "script": {
        "lang": "painless",
        "inline": "ctx.userCount = ctx.message?.users?.size() ?: 0"
      }
    }
  ]
}

Затем в Timelion будет очень легко составить график того, что вам нужно, используя metric='sum:userCount' для суммирования значений userCount и функцию cusum() для получения совокупной суммы userCountover time. Все выражение будет выглядеть так:

.es(index=logstash-*,timefield='dateTime',q='messageType:UserList',metric='sum:userCount').label('Users Online').cusum()

Используя несколько примеров документов, временной ряд выглядит так, что, похоже, это то, что вы ищете.

Пользователи онлайн

person Val    schedule 28.07.2017
comment
Можно ли это сделать без создания дополнительного поля UserCount? - person Goodbye StackExchange; 28.07.2017
comment
Было бы здорово, если бы можно было определить скриптовое поле (например, return params['_source'].message.users.size()) внутри Kibana, а затем использовать его в Timelion, но, к сожалению, пока не поддерживается. - person Val; 28.07.2017
comment
Как насчет индексации пользовательского массива и использования функции для получения размера пользовательского массива? - person Goodbye StackExchange; 31.07.2017
comment
Если вы используете ES 5, у меня есть другое решение. Смотрите мой обновленный ответ. - person Val; 31.07.2017