Обновить
3
0
Сергей@seriych

ClickHouse DBA

Отправить сообщение

Спасибо за читабельное описание sequenceMatch/sequenceCount/windowFunnel, а то иногда оно вроде надо было, но в доке как-то неочевидно описано, что я забивал разбираться надо оно мне или нет.

В комментариях расскажите, какие "непопулярные" функции кликхаус успростили вам жизнь.

Мой фаворит cityHash64(). Когда надо сджойнить или посчитать юники по строкам или по набору колонок, а сами значения этих колонок не нужны, то гораздо дешевле загнать всё это в cityHash64() (лучше cityHash64(tuple()), чтобы с null норм было) и посчитать по одному целому числу, чем по тяжелым строкам или набору колонок. Тоже самое при проверке на IN: cityHash64((col1, col2)) IN (select cityHash64((col1, col2)) ...). И когда сэмплирование надо сделать, тоже пригождается: where cityHash64(id) % 100 < 10.

Ну и assumeNotNull(), избавляющий от злобного Nullable (осторожно, есть нюансы с Nullable(Enum)).

 То есть теперь можно писать красиво JOIN, и оно будет не хуже, чем dictGet‑функции.

Сомнительное утверждение. Это побуждает писать условия на where уже после джойна, что далеко не всегда оптимизируется. Для удобства, и чтобы было "красиво", мы создавали UDF-функции вместо прямого вызова словаря. Типа ipToCountry() - это читабельно, удобно компактно писать, плюс подсказки IDE-шки с этим работают в отличие от dictGet(), плюс внутрь UDF можно дополнительно зашить приведение типов и т.п.

Еще, наверное, стоит упомянуть, что clickhouse некорректно учитывает память, занимаемую словарями, и что можно подкрутить MAX_LOAD_FACTOR для экономии памяти, если такая необходимость есть.

Создадим файл ./clickhouse_init/init-db.sql и подготовим в нем скрипт для создания необходимых таблиц в базе данных:
..duration Float64,
..duration Float64,
...
..duration Float64

Вам где-то надо больше 7 значащих цифр в точности продолжительности событий? Очень сомневаюсь. Скорее всего вы просто так тратите x2 места на диске, x2 памяти на обработку и x2 сетевого трафика (то есть x2 денег работодателя) и пока не замечаете проблем с производительностью. При этом у коллег всё ok:

Да, в нашей внутренней системе мы собираем еще больше данных, но принципы анализа остаются теми же.
..duration Float32,
..duration Float32,
...
..duration Float32

(еще как вариант использовать везде для duration миллисекунды и UInt32/Int32, если ~месяца продолжительности хватает)

CREATE TABLE IF NOT EXISTS default.test_metrics
...
run_timestamp DateTime64(3),
nodeid String,
...
ORDER BY (run_timestamp, nodeid);

Тут вероятно оптимальнее будет что-то вроде: ORDER BY (toDate(run_timestamp), nodeid, run_timestamp) или ORDER BY (nodeid, run_timestamp). Вообще удобно когда отдельная колонка с Date есть (не просто так оно в системных таблицах используется, хотя может показаться избыточным) - она сжимается практически в ноль, и удобнее везде использовать в готовом виде, чем постоянно приводить DateTime.

Немного оффтоп, но если такой упор на вело/СИМ (а на мой взгляд яндекс и раньше никак не подходил для вело), то позволю себе посоветовать заглянуть на https://bikerouter.de. Там 100500 разных профилей построения маршрутов для разных предпочтений катания. Мой любимый "Trekking-Fast-wet" (в основном дороги, но можно и на тропинку съехать). Похожи на него, но поменьше приоритет у дорог: "Randonneur" и "Trekking". По тротуарчикам, наверное, "MTB standard". Наоборот только по дорогам "Road bike" и совсем хардкор "Road Bike (Asia Pacific)".

А, нет - всё-таки зависит от масштаба в браузере, но нетривиально. Если при открытии страницы не 100%, то даже если потом поставить 100%, не перезагружая страницу, то зашакалено даже если масштаб карты туда-сюда двигать. А если поставить масштаб в браузере 100% и перезагрузить страницу, то не зашакалено даже если потом масштаб в браузере изменить и менять масштаб карты.

Я сейчас проверил. У меня как у автора поста всё зашакалено в chrome и vivaldi, а в яндекс-браузере вполне читабельно. Экран 27" 2560x1440, Windows 10, масштаб системы 100%. От масштаба браузера не зависит.

Слева Яндекс-браузер, справа chrome

*масштаб не удалось в точности одинаковый выставить на карте - всегда отличается немного, несмотря на 100% в обоих браузерах.

О, спасибо, оказывается можно это отключить разлогинившись:

Рекомендации доступны пользователям, которые вошли в аккаунт

Только можно вот это не делать, пожалуйста:

Неавторизованные пользователи в будущем смогут видеть общие рекомендации популярных мест в городе

Они уже так на панорамах сделали.

Главные городские ориентиры — Super‑POI

Вот в случайном месте открыл карту, покрутил масштаб.

Смотрим на довольно отдаленном масштабе видно обычную POI некую "Веранда Алтай" (видимо, самое крутое место в регионе?). Крутим чуть крупнее - вокруг озера еще пара POI появляется, пока всё норм. Крутим еще крупнее - внезапно от нашей "крутой" "Веранды" остается пустое место, но появляется Super‑POI "Пляж". Еще чуть крупнее - "Пляж" исчезает, обратно появляется "Веранда", но теперь уже в виде Super‑POI. Еще чуть крупнее - опять появляется пляж, но теперь уже не Super‑POI, а обычной иконкой (заметим, насколько же она читабельнее этого месива пикселей на Super‑POI). И наконец еще крупнее и "Веранда", и "Пляж" оба в виде Super‑POI.

Так что из этого "главные городские ориентиры", если на разных масштабах то одно есть, то другое?

P.S. На самом деле эти Super-POI конечно же автоматически игнорируются глазом как реклама, и смотришь только на нормальные иконки. Но по следам статьи решил обратить внимание, что же они из себя представляют.

Спасибо за столь подробную статью.

Попользуемся, посмотрим. Есть положительные изменения, которые мы, конечно же, оценим как само собой разумеющееся, поэтому не будем об этом.

А вот минусы очень даже заметим.

Единственная реальная причина перекраски дорог с желтого на серое - это "бесшовное" масштабирование. Все остальные перечисленные причины - это просто накидать побольше пунктов, чтобы "продать" эту перекраску. Актуально всё остальное было предыдущие X лет, но никого не беспокоило, пока разметку не нарисовали. Столь глобальное изменение ради одной фичи на самом крупном масштабе - ну такое, звучит опасненько. Например, теперь дороги, реки и ЖД-пути - все плюс-минус одинакового цвета, и дольше понимать где что. Но на первый взгляд пока не так страшно как у гугла, так что может и сойдет.

использование полноценных иконок в таких условиях превращает карты в хаотичный паттерн синих пятен, который забирает слишком много внимания у остальной карты

Вот это вот прям точно описывает впечатление от Super-POI. Бесит это их пестрение на карте. В общем, остановки убрали, теперь больше места, чтобы нарисовать еще больше рекламных иконок - спасибо (нет).

Названия улиц капсом - ну такое. Вон на скриншоте в статье пробел не видно во "ВТОРОЙЭСТАКАДНЫЙ" - каждый напрягаться, чтобы понять, где одно слово заканчивается, другое начинается.

То есть HD‑дороги помогают в ориентировании не только водителям, но ещё и пешеходам, велосипедистам, курьерам, самокатчикам, пассажирам общественного транспорта и всем остальным.

А зимние панорамы мешают всем перечисленным. Передайте, пожалуйста, лучи антидобра тем, кто придумал эту дичь с зимними панорамами.

На будущее: станции Метро/МЦД бы на бОльших масштабах показывать. Причем ступенек так на 5 больших (3-5км). Хотя бы МЦД за МКАДом. Или как слой иметь возможность включать как на 2gis. Постоянно приходится зумиться сильно и мотать карту туда-сюда в поисках ближайшей станции.

То есть когда яйцо под углом не догадались попробовать? Кажется, что при таком методе должно получиться существенно выше. Часть энергии будет переходить во вращательный момент.

В общем есть в нём одна незадокументированная фишка

(процесс дедубликации не моментальный, но не 2 года же)

Именно это и задокументировано прямым текстом: "в неизвестный момент времени, на который вы не можете ориентироваться". Не надо додумывать и считать, что документация вам врёт, потому что вам кажется, что в этой фразе почему-то подразумевается "но не 2 года же".

(справедливости ради, документация иногда действительно врёт, но не в данном случае)

А вам стоит разобраться, почему у вас не происходит дедубликация (если вам это, конечно, нужно):

  • действительно ли данные на одном шарде

  • не лежат ли данные в разных партициях (так тоже не будет дедубликации)

  • настройки типа insert_deduplicate=0 + optimize_skip_merged_partitions=1 могут привести к неудалению дублей даже в одной партиции

  • насколько большие парты с дублями (есть лимиты на слияние слишком больших)

  • как именно вызываете optimize (с final или нет) и каких таблиц и партиций, на всех ли шардах...

  • не падает ли мердж

Может еще что-то забыл и проблема в чем-то еще. Но у нас почти всё на ReplicatedReplacingMergeTree, так что на 99% уверен, что проблема не в КХ (даже не смотря на не самую удачную версию у вас - 1% на это оставляю).

PS. В современных версиях есть настройки, задающие максимальное время до мерджа, что потенциально может избавить от optimize по cron/airflow, но мы до этого еще не обновились, так что не могу сказать, насколько оно норм и какие там грабли.

Можете сами придумать регулярку, которая слова вычленяет на ваш взгляд правильно, и заменить тут простую \w+ на нужную: https://fiddle.clickhouse.com/1a424911-2450-4668-82bc-c27a24b4161b

со \w+ и lowercase получается:

count():                                   32583
uniqExact(word):                           4650
uniq(word):                                4650
uniqCombined(word):                        4657
uniqHLL12(word):                           4663
length(toString(uniqExactState(word))):    74402
length(toString(uniqState(word))):         18603
length(toString(uniqCombinedState(word))): 98505
length(toString(uniqHLL12State(word))):    2651

Примерный uniq дает такой же результат, что и точный uniqExact, но занимает меньше памяти. Но тут данных мало, если найдется файлик пожирнее, разница будет больше.

Не так уж и много памяти сейчас. Вот есть у нас несколько юзеров БД, каждый запустил запрос на количество уникальных по нескольким колонкам. А среди них еще и строковые могут быть. И на практике это реально кучу памяти отъедает. Плюс это еще и медленно. Поэтому приблизительные алгоритмы рулят, особенно которые дают точный результат на маленьком числе групп, а неточность возникает только после тысяч.

Есть разница между тем, что запрос отожрал всю память и если повезет, то не упал и выполнился за время пока ты кофе пошел сделать, и тем, что запрос ничего не отожрал и выполнился за пару секунд (но может быть выдал 123456700 вместо 123456789, какой ужас).

В первом же абзаце статьи: "Главный критерий - нахождение адреса, если написано с ошибками или не дописан он в полной мере." Чуть опечатался и всё, разбиение на слова и точная проверка ломаются сразу. Ну и выше вам показывали про дом с квартирой. Тоже самое с улицей и населенным пунктом может быть.

ИВАНОВ ИВАН ИВАНОВИЧ
и
ИВАН ИВАНОВ
считаются совпадением т.к все уникальные элементы более коротого набора

Мне кажется, что ИВАНОВ ИВАН ИВАНОВИЧ и ИВАНОВ ИВАН ИВАНОВИЧ всё-таки совпадение получше, то есть логично меру для ИВАН ИВАНОВ и ИВАНОВ ИВАН ИВАНОВИЧ видеть хуже.

Возможно, вы не совсем поняли про "последовательности байт" (собственно я и не пояснял особо). Там ищется не максимально длинное совпадение. Там строки разбиваются на все возможные последовательности N байт (для фиксированного N), например: 'ИВАН', 'ВАН ', 'АН И', 'Н ИВ' и т.д. И вот число совпадающих этих наборов сравнивается. Это достаточно хорошо работает с перестановками слов, опечатками и.т.п. (поэтому я и предложил метод автору). Но пункт про нормализацию строк в той или иной степени может быть полезен в каких-то случаях и здесь.

P.S. Я ни разу не специалист в этой теме, не знаю, как лучше будет работать у автора статьи и как лучше будет работать у вас. Я лишь запостил еще один вариант. Кажется, что у каждого метода есть недостатки, выстреливающие в зависимости от ситуации. Собственно не было бы нескольких разных методов если бы это было не так.

В clickhouse для этого есть всякие готовые ngramDistance*(). Неплохо работает для приведенных примеров (даже явно получше, чем в статье для Нарт). Оно смотрит процент совпадающих последовательностей байт в строках - можно это реализовать на удобном вам языке.

Hidden text
with
  ['Эски сары', 'Нарты']
    as queries,
  ['Эски сары кёл', 'Хасаутская', 'Нартов', 'Новый Карачай', 'Мара-Аягъы', 'Кавказская']
  as target_vector
select
  arrayJoin(queries) as query,
  arrayJoin(target_vector) as target,
  ngramDistance(query, target) as similarity1,
  ngramDistanceCaseInsensitiveUTF8(query, target) as similarity2
order by query, similarity2, similarity1
format PrettyCompactMonoBlock
;
    +-query-----+-target--------+-similarity1-+-similarity2-+
 1. | Нарты     | Нартов        |       0.375 |  0.42857143 |
 2. | Нарты     | Эски сары кёл |  0.85714287 |           1 |
 3. | Нарты     | Мара-Аягъы    |   0.9130435 |           1 |
 4. | Нарты     | Новый Карачай |   0.9310345 |           1 |
 5. | Нарты     | Хасаутская    |           1 |           1 |
 6. | Нарты     | Кавказская    |           1 |           1 |
 7. | Эски сары | Эски сары кёл |         0.2 |  0.22222222 |
 8. | Эски сары | Хасаутская    |   0.7419355 |           1 |
 9. | Эски сары | Нартов        |  0.82608694 |           1 |
10. | Эски сары | Кавказская    |  0.87096775 |           1 |
11. | Эски сары | Мара-Аягъы    |  0.93333334 |           1 |
12. | Эски сары | Новый Карачай |   0.9444444 |           1 |
    +-----------+---------------+-------------+-------------+

https://fiddle.clickhouse.com/466ee362-dbff-4161-9553-ae6abcd565ec

А вообще, используйте WebP. Он лучше JPG и его уже везде принимают, кроме пары технически отсталых сайтов.

Из статьи:

Канал.jpg (Хабр не поддерживает формат WebP)

что-то мне подсказывает, что "парочка отсталых сайтов" в реальном мире - это 90+%. И по итогу будет двойное пережатие исходник -> webp -> jpeg, что врядли хорошо отразится на хорошем качестве.

Пишу это только из-за "В марте 2024 года мы снова проведём наше исследование", чтобы следующая статья была оформлена лучше.

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

"спокойно" - если у вас в 4 раза больше денег на сервера

snowflake id или sonyflake id почти всегда лучше, ибо 8 байт и монотонность. Возможно, хуже там где "Отсутствие предсказуемости" - это серьезный фактор. Ну или у вас ну ооочень много юников.

1

Информация

В рейтинге
6 631-й
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Администратор баз данных, Инженер по данным
ClickHouse
Grafana
JavaScript