Возможно ли преобразовать данные JSON в сценарий Elasticseach Painless и выполнить над ним дальнейшие операции? - PullRequest
0 голосов
/ 26 мая 2019

У нас есть большой набор документов в формате JSON для поиска, чтобы найти шаблоны и исторические тенденции. Elasticsearch, кажется, идеально подходит для этой проблемы. Первый трюк заключается в том, что документы представляют собой коллекции из десятков тысяч «вложенных» документов (с заголовком). Второй трюк заключается в том, что эти вложенные документы представляют данные разных типов.

Чтобы учесть это, все поля значений были «закодированы» в виде массива строк, поэтому в JSON было сохранено одно целочисленное значение как «[\" 1 \ »]» и таблица floats выравнивается до "[\" 123.45 \ ", \" 678.9 \ ", ...]" и так далее. (У нас также есть массивы строк, которые не нуждаются в преобразовании.) Хотя это неудобно, я бы подумал, что это будет хорошим компромиссом, учитывая то, как все остальное, задействованное в Elasticsearch, работает.

Особая проблема заключается в том, что эти значения хранимых данных могут представлять битовое поле, из которого нам может потребоваться проверить состояние одного бита. Поскольку это поле будет сохранено как строковый массив из одного элемента, например "[\" 14657 \ "], нам нужно преобразовать его в одно целое число, а затем сдвинуть его несколько раз в нужный бит (или применить маска, если такая функция доступна).

С Elasticsearch я вижу, что могу встраивать «безболезненные» сценарии, но примеры меняются, и мне не удалось найти тот, который показывает, как я могу преобразовать поле данных массива строк произвольной длины в соответствующие типы, для дальнейшего сравнения. Вот мой скрипт запроса в его нынешнем виде.

{
  "_source" : false,
  "from" : 0, "size" : 10,
  "query": {
    "nested": {
      "path": "Variables",
      "query": {
        "bool": {
          "must": {
            "match": {"Variables.Designation": "Big_Long_Variable_Name"}
          },
          "must_not": {
            "match": {"Variables.Data": "[0]"}
          },
          "filter": {
            "script": {
              "script": {
                "source":
                "
                  def vals = doc['Variables.Data'];
                  return vals[0] != params.setting;
                ",
                "params": {
                  "setting": 3
                }
              }
            }
          }
        }
      },
      "inner_hits": {
        "_source": "Variables.Data"
      }
    }
  }
}

Мне нужно каким-то образом преобразовать переменную vals в массив целых чисел, выбрать первое значение, выполнить некоторые битовые операции и выполнить сравнение, чтобы вернуть true или false. В этом примере я надеюсь, что смогу установить «установку» равной битовой позиции, которую я хочу проверить для включения / выключения.

Я уже прошел через упражнение с Elasticsearch, чтобы выяснить, что мне нужно сделать поле Variables.Data ключевым словом, чтобы я мог искать в нем определенные значения. Я понимаю, что это уходит от намерений Elasticsearch, но я все еще думаю, что это может быть лучшим решением по другим причинам. Я создал новый индекс и повторно импортировал свои тестовые документы, и размер индекса вырос примерно на 30%. Это компромисс, на который я хочу пойти, если смогу заставить это работать.

Какие инструменты у меня есть в Painless, чтобы сделать эту работу? (Или я схожу с ума, пытаясь сделать это с помощью этого инструмента?)

1 Ответ

1 голос
/ 01 июня 2019

Я бы посоветовал вам закодировать ваши данные в типы, предусмотренные эластичным поиском, где это возможно (и даже когда нет), чтобы максимально эффективно использовать безболезненно. Например, для битовых строк их можно кодировать как массив из 1 и 0 для упрощения операций с Painless.

Безболезненно, на мой взгляд, все еще примитивно. Сложно отлаживать. Трудно читать. Это трудно поддерживать. И это ужасная идея иметь большие функции в безболезненном.

Чтобы ответить на ваш вопрос, вам в основном нужно проанализировать строку массива безболезненно и поместить ее в один из доступных типов данных, чтобы выполнить желаемое сравнение. Например, для списка вы должны использовать что-то вроде функции split , а затем вручную указывать каждый элемент в результатах как int, float, string и т.д ...

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

POST /_scripts/painless/_execute
{
  "script": {
    "source": """
    ArrayList arr = []; //to start with
    // use arr.add(INDEX, VALUE) to add after parsing
    """,
    "params": {
      "foo": 100.0,
      "bar": 1000.0
    }
  }
}

С другой стороны, если вы сохраните свои данные в предоставленных типах данных ElasticSearch (обратите внимание, что ElasticSearch поддерживает сохранение списков внутри документов), тогда эту задачу будет гораздо проще выполнить в Painless.

Например, вместо my_doc.foo = "[\" 123.45 \ ", \" 678.9 \ ", ...]" в качестве строки для последующего анализа, почему бы не сохранить ее как собственный список с плавающей точкой вместо этого, как my_doc.foo = [123.45, 678.9, ...]?

Таким образом, вы избегаете ненужного кода Painless, необходимого для разбора текстового документа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...