Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
ded86076
Commit
ded86076
authored
Mar 28, 2014
by
antirez
Browse files
HLLCOUNT implemented.
parent
156929ee
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/hyperloglog.c
View file @
ded86076
...
...
@@ -30,6 +30,7 @@
*/
#include <stdint.h>
#include <math.h>
#include "redis.h"
/* The Redis HyperLogLog implementation is based on the following ideas:
...
...
@@ -262,6 +263,41 @@ int hllAdd(uint8_t *registers, unsigned char *ele, size_t elesize) {
}
}
/* Return the approximated cardinality of the set based on the armonic
* mean of the registers values. */
uint64_t
hllCount
(
uint8_t
*
registers
)
{
double
m
=
REDIS_HLL_REGISTERS
;
double
alpha
=
0
.
7213
/
(
1
+
1
.
07
9
/
m
);
double
E
=
0
;
int
ez
=
0
;
/* Number of registers equal to 0. */
int
j
;
for
(
j
=
0
;
j
<
REDIS_HLL_REGISTERS
;
j
++
)
{
uint8_t
reg
;
/* Compute SUM(2^-register[0..i]). */
HLL_GET_REGISTER
(
reg
,
registers
,
j
);
if
(
reg
==
0
)
{
ez
++
;
E
+=
1
;
/* 2^(-reg[j]) is 1 when m is 0. */
}
else
{
E
+=
1
.
0
/
(
2ULL
<<
reg
);
/* 2^(-reg[j]) is the same as 1/2^reg[j]. */
}
}
/* Muliply the inverse of E for alpha_m * m^2 to have the raw estimate. */
E
=
(
1
/
E
)
*
alpha
*
m
*
m
;
/* Apply corrections for small cardinalities. */
if
(
E
<
m
*
2
.
5
&&
ez
!=
0
)
{
E
=
m
*
log
(
m
/
ez
);
/* LINEARCOUNTING() */
}
/* We don't apply the correction for E > 1/30 of 2^32 since we use
* a 64 bit function and 6 bit counters. To apply the correction for
* 1/30 of 2^64 is not needed since it would require a huge set
* to approach such a value. */
return
(
uint64_t
)
E
;
}
/* ========================== HyperLogLog commands ========================== */
/* HLLADD var ele ele ele ... ele => :0 or :1 */
...
...
@@ -299,7 +335,7 @@ void hllAddCommand(redisClient *c) {
}
}
/* Perform the low level ADD operation for every element. */
registers
=
(
uint8_t
*
)
o
->
ptr
;
registers
=
o
->
ptr
;
for
(
j
=
2
;
j
<
c
->
argc
;
j
++
)
{
if
(
hllAdd
(
registers
,
(
unsigned
char
*
)
c
->
argv
[
j
]
->
ptr
,
sdslen
(
c
->
argv
[
j
]
->
ptr
)))
...
...
@@ -315,6 +351,34 @@ void hllAddCommand(redisClient *c) {
addReply
(
c
,
updated
?
shared
.
cone
:
shared
.
czero
);
}
/* HLLCOUNT var -> approximated cardinality of set. */
void
hllCountCommand
(
redisClient
*
c
)
{
robj
*
o
=
lookupKeyRead
(
c
->
db
,
c
->
argv
[
1
]);
uint8_t
*
registers
;
if
(
o
==
NULL
)
{
/* No key? Cardinality is zero since no element was added, otherwise
* we would have a key as HHLADD creates it as a side effect. */
addReply
(
c
,
shared
.
czero
);
}
else
{
/* Key exists, check type */
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
/* If this is a string representing an HLL, the size should match
* exactly. */
if
(
stringObjectLen
(
o
)
!=
REDIS_HLL_SIZE
)
{
addReplyErrorFormat
(
c
,
"HLLCOUNT target key must contain a %d bytes string."
,
REDIS_HLL_SIZE
);
return
;
}
registers
=
o
->
ptr
;
addReplyLongLong
(
c
,
hllCount
(
registers
));
}
}
/* This command performs a self-test of the HLL registers implementation.
* Something that is not easy to test from within the outside.
*
...
...
src/redis.c
View file @
ded86076
...
...
@@ -269,7 +269,8 @@ struct redisCommand redisCommandTable[] = {
{
"bitpos"
,
bitposCommand
,
-
3
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"wait"
,
waitCommand
,
3
,
"rs"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"hllselftest"
,
hllSelftestCommand
,
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"hlladd"
,
hllAddCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
}
{
"hlladd"
,
hllAddCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hllcount"
,
hllCountCommand
,
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
}
};
struct
evictionPoolEntry
*
evictionPoolAlloc
(
void
);
...
...
src/redis.h
View file @
ded86076
...
...
@@ -1449,6 +1449,7 @@ void replconfCommand(redisClient *c);
void
waitCommand
(
redisClient
*
c
);
void
hllSelftestCommand
(
redisClient
*
c
);
void
hllAddCommand
(
redisClient
*
c
);
void
hllCountCommand
(
redisClient
*
c
);
#if defined(__GNUC__)
void
*
calloc
(
size_t
count
,
size_t
size
)
__attribute__
((
deprecated
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment