Как сохранить логический массив и выполнить операции XOR в Elasticsearch?

#elasticsearch

#elasticsearch

Вопрос:

Я хотел бы начать использовать ElasticSearch для сохранения некоторых предварительно вычисленных результатов, которые мне нужно будет сопоставить впоследствии. Этот результат представляет собой 200-размерный битовый массив, связанный с идентификатором.

Чтобы выполнить сопоставление, мне нужно было бы выполнить операцию XOR между входными данными поиска и сохраненными битовыми массивами для моих существующих элементов и отсортировать по количеству оставшихся битов (мощность).

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

Спасибо!

Ответ №1:

Обратите ВНИМАНИЕ: вероятно, вам не следует хранить его как массив, поскольку элементы массива хранятся как вложенные объекты. Кроме того, индексированные массивы не соблюдают исходный порядок. Итак, вы должны сохранить его как keyword .

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

Во-первых: проиндексируйте его как keyword тип, вы захотите убедиться, что ваша keyword длина указывает соответствующую максимальную длину.

 "binary_string" :
   "type" : "keyword",
   "ignore_above" : 256 // <-- Whatever your max binary string length will be
}
  

Второе: Затем вы можете sort выполнить запрос на основе поля сценария, используя безболезненный

 GET binary_test/_search
{
  "sort": [
    {
      "_script" : {
            "type" : "string",
            "script" : {
                "lang": "painless",
                "source": """
                def val1 = new BigInteger(doc['binary_string'].value, 2);
                val1.xor(new BigInteger("000000000", 2)).toString(2) // whatever your binary string is that you are comparing to
                """
            },
            "order" : "asc"
        }
    }
  ]
}
  

Соображения:

  • Причина сортировки по строковому значению xor заключается в том, что числа хранятся как float , и возможная потеря точности может дорого вам обойтись.
  • Построение двух BigInteger значений и использование BigInteger#xor может быть медленнее, чем простое перебирание двух строк и самостоятельное создание новой, я бы поэкспериментировал с этим, если вы заботитесь о производительности.

Если вас не волнует фактическое число битов, вы могли бы сделать следующее, просто будьте осторожны с несоответствием длины bitarray (если это возможно при вашем вводе)

 "_script" : {
   "type" : "number",
       "script" : {
                "lang": "painless",
                "source": """
                def val1 = doc['binary_string'].value;
                def val2 = "000000000"; // <-- the string you care about
                def count = 0;
                for(int i; i < val2.length; i  ) {
                  if (val1.charAt(i) != val2.charAt(i)) {
                    count  ;
                  }
                }
                count
                """
            },