Поиск значений массива, кроме списка позиций - PullRequest
0 голосов
/ 02 марта 2019

У меня есть десятки миллионов документов, подобных следующему.

{
    id: "<some unit test id>",
    groupName: "<some group name>",
    result: [
        1, 0, 1, 1, ... 1
    ]
}

Поле результата представляет собой массив из 200 чисел, 0 или 1.

Моя задача - найти, учитывая groupName, скажем, «group17» и несколько чисел, скажем,3, 8, 27 найти все документы, чьи элементы результирующего массива для groupName все равны 1, игнорируя значения в позициях 3, 8, 27.

Был бы признателен, если бы кто-то мог указать, если есть быстрыйИщите его.

1 Ответ

0 голосов
/ 04 марта 2019

Один из способов добиться того, чего вы хотите, - это добавить другое поле, которое содержит эквивалентное целочисленное значение набора битов, содержащегося в массиве result, а затем использовать побитовую операцию AND.

Например, скажем,что результирующий массив равен

result: [1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0]

Целочисленное значение, представленное этими битами, равно 1470, поэтому я сохраняю следующий документ:

PUT test/doc/1
{
    "groupName": "group12",
    "result": [
        1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0
    ],
    "resultLong": "1470"
}

Теперь запрос будет выглядеть следующим образом

POST test/_search 
{
  "query": {
    "script": {
      "script": {
        "source": """
        // 1. create a BigInt out of the resultLong value we just computed
        def value = new BigInteger(doc['resultLong'].value.toString());

        // 2. create a bitset filled with 1's except for those positions specified in the ignore parameters array
        def comp = IntStream.range(1, 12).mapToObj(i -> params.ignore.contains(i - 1) ? "0" : "1").collect(Collectors.joining());

        // 3. create a BigInt out of the number we've just created
        def compare = new BigInteger(comp, 2);

        // 4. compare both using a bitwise AND operation
        return value.and(compare).equals(compare);
        """,
        "params": {
          "ignore": [1, 4, 10]
        }
      }
    }
  }
}

Шаг 2 сначала создает строку длиной 11, заполненную 1 или 0, если текущий индекс находится в массиве params.ignore.В итоге получается строка "10110111110".

. На шаге 3 из этой строки создается BigInteger (в базе 2).

На шаге 4 сравниваются оба числа по битам, т. Е. Документбудет возвращено только в том случае, если оба числа имеют 1 в одинаковых позициях.

Примечание: для массивов длины 200 вместо него необходимо использовать IntStream.range(1, 201).

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