помещение
Проекты или требования, разработанные на определенный период времени в будущем, будут широко использоватьсяRedis
, пока бизнес не слишком занят в это время, найдите время, чтобы просмотреть и просмотретьRedis
связанный контент. Только что увидел блогUV
а такжеPV
Статистика, я думал о том, что было упомянуто в книге, которую я недавно прочиталHyperLogLog
тип данных, поэтому найдите время, чтобы проанализировать его использование и сценарии использования (Пока не исследуюHyperLogLog
Принцип реализации).Redis
серединаHyperLogLog
тип данныхRedid 2.8.9
Введено, убедитесь, что при использованииRedis
Версия>= 2.8.9
.
Введение в Гиперлоглог
基数计数(cardinality counting)
, который обычно используется для подсчета количества уникальных элементов в наборе. Очень распространенный пример — статистика статьиUV
(Unique Visitor
, независимый посетитель, обычно понимаемый как клиентIP
). В условиях большого объема данных для достижения кардинального подсчета в большинстве случаев не выбирают хранение элементов полного кардинального множества, поскольку можно рассчитать затраты памяти на хранение. средний размер каждого учитываемого элемента32bit
, то если будет подсчитано 100 миллионов данных, занимаемый объем памяти составит:
-
32 * 100000000 / 8 / 1024 / 1024 ≈ 381M
.
Если имеется несколько наборов и разрешено вычислять объединенные результаты подсчета нескольких наборов, сложность этой операции может быть разрушительной. Поэтому не буду использоватьBitmap
,Tree
илиHashSet
Структура данных непосредственно хранит набор счетных элементов для подсчета, но исходя из того, что не преследуется абсолютно точных результатов подсчета, для подсчета используется вероятностный алгоритм подсчета кардинальности.В настоящее время существует три распространенных алгоритма вероятности:
-
Linear Counting(LC)
. -
LogLog Counting(LLC)
. -
HyperLogLog Counting(HLL)
.
Таким образом, HyperLogLog на самом деле представляет собой вероятностный алгоритм подсчета количества элементов, который не уникален для Redis.Redis реализует HyperLogLog на основе языка C и предоставляет соответствующие записи API команд.
Redis
авторAntirez
для воспоминанийPhilippe FlajoletИзучение комбинаторики и анализ мощностных алгоритмов, поэтому в дизайнеHyperLogLog
используется в командеPhilippe Flajolet
инициалы имениPF
как префикс. То есть,Philippe Flajolet
кандидат наукHLL
Основной вклад в алгоритм, но на самом деле он неRedis
серединаHyperLogLog
Разработчик типа данных. К сожалениюPhilippe Flajolet
Доктор умер в Париже 22 марта 2011 года из-за болезни. этоPhilippe Flajolet
Доктор фото из Википедии:
Redis
который предоставилHyperLogLog
Характеристики типа данных:
- Основные характеристики: Использование
HyperLogLog Counting(HLL)
выполнить,Выполнять только расчет кардинальности, метаданные не сохраняются.. - Использование памяти:
HyperLogLog
каждыйKEY
самый занятый12K
объем памяти, который может быть рассчитан близко к2^64
Мощность различных элементов, его место для хранения хранится в разреженной матрице, а занимаемая площадь очень мала.Только когда число элементов подсчета постепенно увеличивается, а пространство, занимаемое разреженной матрицей, постепенно превышает порог, это будет преобразуется в плотную матрицу за один раз.Он будет занят после того, как станет плотной матрицей12K
пространство памяти. - Погрешность подсчета: результат базового подсчета составляет одну стандартную ошибку (
Standard Error
)за0.81%
Приблизительное значение , когда количество данных невелико, результатом также может быть точное значение.
Небольшой объем памяти (до 12 КБ на KEY)HyperLogLog
самое большое преимущество, который имеет два относительно очевидных ограничения:
- Вычисленный результат не является точным значением, имеется стандартная ошибка, которая обусловлена вероятностным характером алгоритма.
- Метаданные кардинальности не сохраняются, что не подходит для сценариев, в которых необходимо использовать метаданные для анализа данных.
Использование команды HyperLogLog
Redis
который предоставилHyperLogLog
Есть три команды для типа данныхAPI
:PFADD
,PFCOUNT
а такжеPFMERGE
.
PFADD
PFADD
Параметры команды следующие:
PFADD key element [element …]
Версии Redis, поддерживающие эту команду: >= 2.8.9 Сложность времени: сложность добавления элемента составляет O (1)
- Функция: преобразует все параметры элемента
element
добавить в ключ какkey
изHyperLogLog
в структуре данных.
PFADD
Последовательность выполнения команды следующая:
PFADD
Команда используется следующим образом:
127.0.0.1:6379> PFADD food apple fish
(integer) 1
127.0.0.1:6379> PFADD food apple
(integer) 0
127.0.0.1:6379> PFADD throwable
(integer) 1
127.0.0.1:6379> SET name doge
OK
127.0.0.1:6379> PFADD name throwable
(error) WRONGTYPE Key is not a valid HyperLogLog string value.
Несмотря на то чтоHyperLogLog
Структура данных, по сути, представляет собой строку, но ее нельзяString
ТипKEY
использоватьHyperLogLog
связанные команды.
PFCOUNT
PFCOUNT
Параметры команды следующие:
PFCOUNT key [key …]
Версии Redis, поддерживающие эту команду: >= 2.8.9 Временная сложность: сложность возврата значения количества элементов одного HyperLogLog составляет O (1), а среднее постоянное время относительно невелико. Когда параметр представляет собой несколько ключей, сложность равна O(N), а N — количество ключей.
- когда
PFCOUNT
команда с помощью одногоkey
, возвращает значение, хранящееся в данном ключеHyperLogLog
приблизительная кардинальность структуры данных или возвращается, если ключ не существует0
. - когда
PFCOUNT
использование командымногоиндивидуальныйkey
, возвращает все сохраненное в заданномHyperLogLog
Приблизительная мощность объединения структур данных, то есть объединение всехHyperLogLog
объединить структуры данных во временнуюHyperLogLog
структуру данных, а затем рассчитать приблизительную кардинальность.
PFCOUNT
Команда используется следующим образом:
127.0.0.1:6379> PFADD POST:1 ip-1 ip-2
(integer) 1
127.0.0.1:6379> PFADD POST:2 ip-2 ip-3 ip-4
(integer) 1
127.0.0.1:6379> PFCOUNT POST:1
(integer) 2
127.0.0.1:6379> PFCOUNT POST:1 POST:2
(integer) 4
127.0.0.1:6379> PFCOUNT NOT_EXIST_KEY
(integer) 0
PFMERGE
PFMERGE
Параметры команды следующие:
PFMERGE destkey sourcekey [sourcekey ...]
Версии Redis, поддерживающие эту команду: >= 2.8.9 Временная сложность: O(N), где N — количество объединяемых структур данных HyperLogLog, постоянное время выполнения этой команды относительно велико.
- Функция: поставить несколько
HyperLogLog
Структуры данных объединяются в новый ключ какdestkey
изHyperLogLog
структура данных, объединеннаяHyperLogLog
мощность близка ко всем входамHyperLogLog
Видимый набор (Observed Set
) мощности объединения. - Возвращаемое значение команды: будет возвращаться только строка
OK
.
PFMERGE
Команда используется следующим образом
127.0.0.1:6379> PFADD POST:1 ip-1 ip-2
(integer) 1
127.0.0.1:6379> PFADD POST:2 ip-2 ip-3 ip-4
(integer) 1
127.0.0.1:6379> PFMERGE POST:1-2 POST:1 POST:2
OK
127.0.0.1:6379> PFCOUNT POST:1-2
(integer) 4
Случай использования HyperLogLog для подсчета UV
Предположим, теперь есть простой сценарий, который заключается в подсчете сообщений в блоге.UV
,ТребоватьUV
Подсчет не обязательно должен быть точным, и при этом он не должен сохранять клиента.IP
данные. В следующем сценарии используйтеHyperLogLog
Напишите простую программу и закодируйте реализацию.
Последовательность шагов в этом процессе может быть скорректирована, но выполняемые операции в основном одинаковы. Кратко предположим, что контент и статистические данные статьи возвращаются фоновым сервисом, а два интерфейса разработаны отдельно. представлятьRedis
расширенный клиентLettuce
полагаться:
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Кодировка следующая:
public class UvTest {
private static RedisCommands<String, String> COMMANDS;
@BeforeClass
public static void beforeClass() throws Exception {
// 初始化Redis客户端
RedisURI uri = RedisURI.builder().withHost("localhost").withPort(6379).build();
RedisClient redisClient = RedisClient.create(uri);
StatefulRedisConnection<String, String> connect = redisClient.connect();
COMMANDS = connect.sync();
}
@Data
public static class PostDetail {
private Long id;
private String content;
}
private PostDetail selectPostDetail(Long id) {
PostDetail detail = new PostDetail();
detail.setContent("content");
detail.setId(id);
return detail;
}
private PostDetail getPostDetail(String clientIp, Long postId) {
PostDetail detail = selectPostDetail(postId);
String key = "puv:" + postId;
COMMANDS.pfadd(key, clientIp);
return detail;
}
private Long getPostUv(Long postId) {
String key = "puv:" + postId;
return COMMANDS.pfcount(key);
}
@Test
public void testViewPost() throws Exception {
Long postId = 1L;
getPostDetail("111.111.111.111", postId);
getPostDetail("111.111.111.222", postId);
getPostDetail("111.111.111.333", postId);
getPostDetail("111.111.111.444", postId);
System.out.println(String.format("The uv count of post [%d] is %d", postId, getPostUv(postId)));
}
}
Выходной результат:
The uv count of post [1] is 4
Можно использовать большее количество различных клиентовIP
перечислитьgetPostDetail()
, а затем посчитайте ошибку.
Не по теме - как правильно считать УФ
Если вам нужна точная статистикаUV
, необходимо обратить внимание на несколько моментов:
- Память или емкость диска должны быть соответствующим образом подготовлены, потому что, согласно текущему алгоритму подсчета количества элементов, нет алгоритма, который может точно считать без сохранения метаданных.
- Если необходимо провести анализ поведения пользователей, то метаданные в конечном итоге должны быть сохранены, что должно опираться на систему больших данных.У автора нет опыта в этом отношении, поэтому я пока не буду об этом говорить.
Предполагая, что без учета стоимости памяти мы все еще можем использоватьRedis
делать это точно и в режиме реального времениUV
Статистика, простота в использованииSet
тип данных, добавитьUV
просто используйтеSADD
команда, статистикаUV
просто используйтеSCARD
команда (временная сложностьO(1)
, вы можете использовать его с уверенностью). Пример:
127.0.0.1:6379> SADD puv:1 ip-1 ip-2
(integer) 2
127.0.0.1:6379> SADD puv:1 ip-3 ip-4
(integer) 2
127.0.0.1:6379> SCARD puv:1
(integer) 4
Если эта статистика отображается только на стороне пользователя, то можно использовать асинхронный дизайн:
При небольшом объеме функции всех вышеперечисленных приложений могут выполняться в одном сервисе, а очередь сообщений может быть заменена асинхронной схемой пула потоков.
резюме
Эта статья является лишь кратким введениемHyperLogLog
использование и статистикаUV
сценарии использования. В общем: в сценариях, где (1) объем необработанных данных огромен, (2) требования к использованию памяти как можно меньше, (3) есть определенная ошибка в подсчете и (4) хранение метаданные не требуются, их можно использовать первыми.HyperLogLog
считать.
Использованная литература:
(Конец этой статьи c-3-d e-a-20191117)
Технический публичный аккаунт ("Throwable Digest"), который время от времени выкладывает оригинальные технические статьи автора (никогда не занимайтесь плагиатом и не перепечатывайте):
Развлекательный публичный аккаунт («Скульптуры из песка каждый день») выбирает интересные фотографии, тексты и видео о скульптурах из песка, чтобы время от времени публиковать их, чтобы облегчить жизнь и работу: