• Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, я не знал, что там речь шла именно о популярных/непопулярных ключах
    Почему O(1) нельзя в данном случае ? Всегда можно сделать размер таблицы n^2 и захешировать, в среднем за 2 раза без коллизий сойдётся. Но с одной стороны так много памяти жалко, с другой, даже, если там будет всего лишь 10к интов, то оно даже в L3 не уложится (нужно 400 мб для этого, а стандавртный серверный L3 обычно 128/256 мб)
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса

    floppa322, я вот решил следующее посчитать. Допустим я не буду вставлять конфликтующие ключи. А просто буду вести их список. Долг типа. Вот получилось так на 5 млн.

    2023-07-28 20:06:28,511 : [INFO] - Start demo
    2023-07-28 20:06:29,417 : [INFO] - Populated successfully!
    2023-07-28 20:06:29,417 : [INFO] - Inserted : 3160854
    2023-07-28 20:06:29,419 : [INFO] - Collision list size : 1839146
    2023-07-28 20:06:29,419 : [INFO] - Hash set physical size is 5000000 slots (20000000 bytes)
    2023-07-28 20:06:29,419 : [INFO] - Inserted/slots ratio : 63%
    2023-07-28 20:06:29,419 : [INFO] - Finish

    Из 5 лямов успешно вставились порядка 3.1 млн. Долговых ключей на 1.8. Хорошая новость
    их хотя-бы не так много. Далее я могу рекурсивно применить алгоритм построения этой-же
    таблицы к списку долговых ключей. Но теперь мне уже не нужно 5 млн слотов. Я сразу создаю
    1.8. И если эта геометрическая прогрессия работает (100% - 63% = 37%) то каждый раз
    я буду получать треть от оригнального размера. Хеш функцию в данном случае можно
    даже не менять. Просто меняется у нас остаток от деления. Будет пирамида таблиц.


    Если честно, у меня пока нет никаких мыслей, как это можно развить, чтобы было O(1) без жирных констант на contains
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, и да, нужно, чтобы запросов, где на contains/get было false/null, было мало, иначе в этом подходе не будет смысла особого
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, кстати, насчёт "skewed histograms" на самом деле, хорошую идею подкинул, если такой шаблон встретился где-то.
    Действительно, можно отсортировать данные по частоте заросов на них, скажем на 10% объектов приходится 90% запросов contains/get, тогда можно с обычным линейным пробированием эти 10% запихать первыми (так, чтобы distance от места вставки до реального места был не больше 1.05 скажем), а остальные 90% запихать потом. Тогда мат. ожидание кеш мисса будет близко к 1.

    Единственный минус это большие таблицы. То есть, например, может так получиться, чтобы сохранить инвариант distance <= 1.05 для 10% объектов может потребоваться массив размером, например, 60n, если данных очень много. Из-за того что вероятность коллизии как квадрат растёт от n, к сожалению
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, ну если речь идёт о статичной таблице (однажды построилась и далее с неё только читают, не модифицируют), то кукушка будет пробовать строиться, пока не построится так, чтобы каждому элементу было отведено место (не было циклов), ну а дальше просто запросы get/contains в зависимости от того мапа это или сет, ничего никуда больше перемещаться не будет))
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, ну я хотел либо попробовать похешировать столько раз, чтобы distance от места вставки до реального расположения был небольше какой-то константы (как в робин гуде) ну и дальше что-то поулучшать там. Либо придумать так, чтобы кукушка из 2-х рандомных меств памяти не читала, либо читала но редко
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, не понимаю, как оно за разумное время могло сработать при 5'000'000 в 5'008'333 слотов. Вот, например, рассмотрим момент, когда вставилось 2'500'000 ключей (т.е. load factor ~ 0.5) теперь осталось вставить ещё столько же ключей и для каждого вероятность, что он вызовет коллизию не меньше 0.5 (и она будет расти по мере продвижения), то есть после момента, как вставилось без коллизий 2.5кк ключей вероятность, что остальные вставятся без коллизий не меньше 0.5^2'500'000
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, а какие ключи (равномерное распределение, нормальное распределение, инкрементальные значения и т.д.) ? какая хеш функция ? с какой попытки сошлось ?
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса

    Алгоритм примерно такой:
    1) Берем размер хеш-таблицы в n = size(K). Метод открытой адресации.
    2) Берем любую хеш-функцию (по области определения больше чем n
    SHA1, MD5, xxhash, mur-mur-hash)
    3) Начинаем наполнять таблицу.
    4) Как только детектирована коллизия - удаляем старую таблицу и создаем новую
    с размером например 120% от исходного n.
    5) Повторяем алгортм до тех пор пока не будут расставлены все ключи.

    Такой подход, к сожалению, сходится к ~n^2 памяти


    Изучать хеширование на базе целых чисел - вобщем-то не интересно. Более общий случай - это
    строки (String) и я-бы делал эксперименты со строками и с реальными данными (мобильные
    телефоны емейлы налоговые номера и прочее). Целые числа - это .... слишком синтетические
    тесты и их результаты потом никуда натянуть нельзя.

    А как же какой-нибудь Map(id, User) ))
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, внешняя и все внутренние таблицы могут быть выделены в непрерывном куске памяти, только вот из-за того, что размер внутренней константный, перерасход памяти получается порядка 10-16n
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, читал :)
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, да не, в том исходнике я исключительно тестировал за сколько он подберёт нужную хеш функцию )
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, ну я пытался сделать эмуляцию заполнения внутренней хеш таблицы, в данном случае с load_factor = 16/14. Смотрел за сколько попыток в среднем это произойдёт (найдётся h2i что не будет коллизий)
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, она, например, в ClickHouse'е используется для интов + как внутрення часть для cityHash для строк
    ну и я сам посмотрел на некоторых дата-сетах у неё хорошее распределение
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, о, вот это её минус главный, внешняя таблица ~2n, а размер внутренней ~5, если до ближайшей степени 2, то 8, и того 2n * 8 = 16n
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, ты сначала функцией h1 хешируешь во внешнюю хеш таблицу итемы, а потом для каждой ячейки внешней хеш таблицы подбираешь такую h2i, что все итемы ячейки захешируются без коллизий
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, немного не понял как тут поможет кукушка, можно подробнее плз )

    Ну и я про кукушку говорил в контексте того, чтобы contains всегда за O(1), не амортизированно
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, короче выяснил, что для некоторого набора данных (ключей) существуют такие параметры (на картинке - evil_param), что если нарисовать граф, где вершина - это параметр, а ребро - текущий ключ + текущий параметр, то появляется цикл в таком графе

    Поборосял с этим дефолтным способом: если алгоритм сильно много итераций не сходится, то меняю параметр на рандомный и пытаясь заново, вроде работает

    Как я понял, с инкрементальными seed'ами просто вероятность в такой цикл попасть больше

    Граф
    Написано
  • Seed для CRC32?

    Lite_stream
    @Lite_stream Автор вопроса
    mayton2019, вот гпт 3.5 дал мне ответ, хотя и довольно поверхностный, хотелось бы мат. обоснование


    Да, для данной конкретной ситуации с хеш-функцией CRC32 можно предложить математическое объяснение такого поведения.

    CRC32 - это циклический редундантный код (Cyclic Redundancy Check), который обычно используется для обнаружения ошибок в данных. Он оперирует с битами данных и вычисляет контрольную сумму для обнаружения ошибок в передаче данных.

    При использовании CRC32 в вашем коде в качестве параметра хеш-функции для хэш-таблицы, вы фактически создаете некоторую последовательность хешей, каждый из которых зависит от предыдущего. Так как CRC32 обрабатывает данные по битам и вычисляет контрольную сумму, его свойства обеспечивают некоторую случайность и разнообразие в вычисленных хеш-значениях.

    Когда вы используете хеш с предыдущей итерации для получения нового хеша (25-я строка), вы создаете последовательность хешей, которая зависит от предыдущих значений. Это приводит к тому, что каждый следующий хеш зависит от предыдущего и от входных данных (ключей), и, таким образом, обеспечивает разнообразие хешей. Кроме того, при каждом исполнении цикла происходит пересчет хеш-значения с новым параметром, что увеличивает разнообразие хешей в процессе.

    С другой стороны, если вы используете обычный инкремент в качестве параметра хеш-функции (40-я строка), то вы просто увеличиваете параметр на 1 на каждой итерации. Это не создает достаточное разнообразие в хеш-значениях для обеспечения успешного поиска хеша без коллизий.

    Таким образом, математическое объяснение заключается в том, что использование CRC32 и его свойства циклического редундантного кода, а также зависимость от предыдущего значения, обеспечивают разнообразие хешей при использовании хеша с предыдущей итерации. Это позволяет алгоритму быстро находить подходящий параметр для успешного заполнения бакета без коллизий.
    Написано