hash_arr Array(UInt64)
)
ENGINE = MergeTree
ORDER BY case_id
SETTINGS index_granularity = 8192
В ней 27 200 строк, массивы в hash_arr содержат от 1 до 14 элементов.
Мне нужно сравнить значения hash_arr в каждой строке с каждой (перебором по возрастанию case_id) и для каждой строки найти case_id первой, соответствующую выражению "кол-во общих элементов в массивах, деленное на половину суммы длин сравниваемых массивов больше 0.25"
Написал такой запрос. реализующий 2 вложенных цикла по массиву массивов :
select arrayMap(x -> case_id_arr_arr[arrayFirstIndex(a -> a > 0.25, arrayMap(y -> length(arrayIntersect(x, y)) / (length(x) + length(y)), a.hash_arr_arr))], a.hash_arr_arr)
from (
select groupArray(hash_arr) hash_arr_arr, groupArray(case_id) case_id_arr_arr
from src_cases_11_1
) a
Получаю: "Code: 241, e.displayText() = DB::Exception: Memory limit (for query) exceeded: would use 24.01 GiB (attempt to allocate chunk of 4295098368 bytes), maximum: 23.28 GiB: while executing 'FUNCTION arrayMap(__lambda :: 2, hash_arr_arr :: 3) -> arrayMap(lambda(tuple(x), arrayElement(case_id_arr_arr, arrayFirstIndex(lambda(tuple(a), greater(a, 0.25)), arrayMap(lambda(tuple(y), divide(length(arrayIntersect(x, y)), plus(length(x), length(y)))), hash_arr_arr)))), hash_arr_arr) Array(Int64) : 1' (version 21.3.8.76 (official build))"
Что делать ? По моим прикидкам, объем массива hash_arr_arr в памяти никак не более 2 Мб, объем итогового массива 27200 * 8 - тоже явно не хватит для переполнения.
При ограничении в исходной таблице в 9-10 тысяч строк запрос успешно отрабатывает за примерно 30 секунд - на мой взгляд, тоже многовато
Такое ощущение, что после выхода из arrayFirstIndex в очередной итерации - ее данные остаются в памяти. Тогда да, 27 тысяч раз по 2 Мб вполне могут вызвать переполнение при 24 Гб свободных
https://kb.altinity.com/altinity-kb-functions/array-like-memory-usage/ Это ожидаемо, и это не бага
КХ делает копию массивов переданных в лямбду для каждой итерации как тупое решение попробуйте max_threads = 1 но скорее всего это нельзя решить через arrayMap и массивы, надо пробовать разворачивать массивы в строки и делать джойн
Именно с этого и начал (данные в src_cases_11_1 это результат groupArray исходной таблицы с 500к) - та же беда, нехватка памяти
Вот, я не стал сворачивать левую часть сравнения в массив, только правую и по ней итерирую с помощью arrayMap: with src as ( select groupArray(hash_arr) hash_arr_arr, groupArray(case_id) case_id_arr_arr from src_cases_11_1 ) select src.case_id_arr_arr[arrayFirstIndex(a -> a > 0.25, arrayMap(y -> length(arrayIntersect(s.hash_arr, y)) / (length(s.hash_arr) + length(y)), src.hash_arr_arr))] from src_cases_11_1 s cross join src DB::Exception: Memory limit (for query) exceeded: would use 24.02 GiB (attempt to allocate chunk of 8589934592 bytes), maximum: 23.28 GiB (version 21.3.8.76 (official build))
А после завершения каждой итерации эти копии удаляются ? Если нет, то возникают серьезные вопросы к реализации arrayMap в CH
Обсуждают сегодня