Skip to content

Commit d4502ca

Browse files
committed
Merge main
2 parents 161f6a7 + f84c585 commit d4502ca

File tree

76 files changed

+1405
-293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1405
-293
lines changed

build/components/example.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@
1111
GO_OUTPUT = 'Output:'
1212
TEST_MARKER = {
1313
'java': '@Test',
14+
'java-sync': '@Test',
15+
'java-async': '@Test',
16+
'java-reactive': '@Test',
1417
'c#': '\[Fact\]|\[SkipIfRedis\(.*\)\]'
1518
}
1619
PREFIXES = {
1720
'python': '#',
1821
'node.js': '//',
1922
'java': '//',
23+
'java-sync': '//',
24+
'java-async': '//',
25+
'java-reactive': '//',
2026
'go': '//',
2127
'c#': '//',
2228
'redisvl': '#',

config.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ tagManagerId = "GTM-TKZ6J9R"
4545
gitHubRepo = "https://github.com/redis/docs"
4646

4747
# Display and sort order for client examples
48-
clientsExamples = ["Python", "Node.js", "Java Sync", "Java Async", "Java Reactive", "Go", "C#", "RedisVL"]
48+
clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#", "RedisVL"]
4949
searchService = "/convai/api/search-service"
5050
ratingsService = "/docusight/api/rate"
5151

@@ -59,9 +59,9 @@ rdi_cli_latest = "latest"
5959
[params.clientsConfig]
6060
"Python"={quickstartSlug="redis-py"}
6161
"Node.js"={quickstartSlug="nodejs"}
62-
"Java sync"={quickstartSlug="jedis"}
63-
"Java async"={quickstartSlug="lettuce"}
64-
"Java reactive"={quickstartSlug="lettuce"}
62+
"Java-sync"={quickstartSlug="jedis"}
63+
"Java-async"={quickstartSlug="lettuce"}
64+
"Java-reactive"={quickstartSlug="lettuce"}
6565
"Go"={quickstartSlug="go"}
6666
"C#"={quickstartSlug="dotnet"}
6767
"RedisVL"={quickstartSlug="redis-vl"}

content/commands/bf.reserve/index.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,13 @@ Though the filter can scale up by creating sub-filters, it is recommended to res
5050
sub-filters requires additional memory (each sub-filter uses an extra bits and hash function) and consume further CPU time than an equivalent filter that had
5151
the right capacity at creation time.
5252

53-
The number of hash functions is `-log(error)/ln(2)^2`.
54-
The number of bits per item is `-log(error)/ln(2)` ≈ 1.44.
53+
The optimal number of hash functions is `ceil(-ln(error_rate) / ln(2))`.
5554

56-
* **1%** error rate requires 7 hash functions and 10.08 bits per item.
57-
* **0.1%** error rate requires 10 hash functions and 14.4 bits per item.
58-
* **0.01%** error rate requires 14 hash functions and 20.16 bits per item.
55+
The required number of bits per item, given the desired `error_rate` and the optimal number of hash functions, is `-ln(error_rate) / ln(2)^2`. Hence, the required number of bits in the filter is `capacity * -ln(error_rate) / ln(2)^2`.
56+
57+
* **1%** error rate requires 7 hash functions and 9.585 bits per item.
58+
* **0.1%** error rate requires 10 hash functions and 14.378 bits per item.
59+
* **0.01%** error rate requires 14 hash functions and 19.170 bits per item.
5960

6061
## Required arguments
6162

@@ -90,7 +91,7 @@ Non-scaling filters requires slightly less memory than their scaling counterpart
9091
When `capacity` is reached, an additional sub-filter is created.
9192
The size of the new sub-filter is the size of the last sub-filter multiplied by `expansion`, specified as a positive integer.
9293

93-
If the number of elements to be stored in the filter is unknown, you use an `expansion` of `2` or more to reduce the number of sub-filters.
94+
If the number of items to be stored in the filter is unknown, you use an `expansion` of `2` or more to reduce the number of sub-filters.
9495
Otherwise, you use an `expansion` of `1` to reduce memory consumption. The default value is `2`.
9596
</details>
9697

content/commands/ft.search/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ syntax: "FT.SEARCH index query \n [NOCONTENT] \n [VERBATIM] \n [NOSTOPWORDS]
283283
\ \n [WITHPAYLOADS] \n [WITHSORTKEYS] \n [FILTER numeric_field min max [ FILTER\
284284
\ numeric_field min max ...]] \n [GEOFILTER geo_field lon lat radius m | km | mi\
285285
\ | ft [ GEOFILTER geo_field lon lat radius m | km | mi | ft ...]] \n [INKEYS count\
286-
\ key [key ...]] [ INFIELDS count field [field ...]] \n [RETURN count identifier\
286+
\ key [key ...]] \n [INFIELDS count field [field ...]] \n [RETURN count identifier\
287287
\ [AS property] [ identifier [AS property] ...]] \n [SUMMARIZE [ FIELDS count field\
288288
\ [field ...]] [FRAGS num] [LEN fragsize] [SEPARATOR separator]] \n [HIGHLIGHT\
289289
\ [ FIELDS count field [field ...]] [ TAGS open close]] \n [SLOP slop] \n [TIMEOUT\

content/commands/json.mget/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Return the values at `path` from multiple `key` arguments
3838

3939
{{% warning %}}
4040
When cluster mode is enabled, all specified keys must reside on the same [hash slot](https://redis.io/docs/latest/operate/oss_and_stack/reference/cluster-spec/#key-distribution-model).
41+
42+
When the database has more than one shard, and the specified keys reside in different shards, Redis will not report a CROSSSLOT error (to avoid breaking changes) and the results may be partial.
43+
44+
4145
{{% /warning %}}
4246

4347
[Examples](#examples)

content/commands/latency-histogram/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ Each histogram consists of the following fields:
5454
* Each bucket represents a latency range
5555
* Each bucket covers twice the previous bucket's range
5656
* Empty buckets are excluded from the reply
57-
* The tracked latencies are between 1 microsecond and roughly 1 second
57+
* The tracked latencies are between 1 nanosecond and roughly 1 second
5858
* Everything above 1 second is considered +Inf
59-
* At max, there will be log2(1,000,000,000)=30 buckets
59+
* At max, there will be log2(1,000,000,000) = 30 buckets
6060

6161
This command requires the extended latency monitoring feature to be enabled, which is the default.
6262
If you need to enable it, call `CONFIG SET latency-tracking yes`.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Learn how to use Redis pipelines and transactions
13+
linkTitle: Pipelines/transactions
14+
title: Pipelines and transactions
15+
weight: 2
16+
---
17+
18+
Redis lets you send a sequence of commands to the server together in a batch.
19+
There are two types of batch that you can use:
20+
21+
- **Pipelines** avoid network and processing overhead by sending several commands
22+
to the server together in a single communication. The server then sends back
23+
a single communication with all the responses. See the
24+
[Pipelining]({{< relref "/develop/use/pipelining" >}}) page for more
25+
information.
26+
- **Transactions** guarantee that all the included commands will execute
27+
to completion without being interrupted by commands from other clients.
28+
See the [Transactions]({{< relref "/develop/interact/transactions" >}})
29+
page for more information.
30+
31+
## Execute a pipeline
32+
33+
To execute commands in a pipeline, you first create a pipeline object
34+
and then add commands to it using methods that resemble the standard
35+
command methods (for example, `set()` and `get()`). The commands are
36+
buffered in the pipeline and only execute when you call the `sync()`
37+
method on the pipeline object.
38+
39+
The main difference with the pipeline commands is that they return
40+
`Response<Type>` objects, where `Type` is the return type of the
41+
standard command method. A `Response` object contains a valid result
42+
only after the pipeline has finished executing. You can access the
43+
result using the `Response` object's `get()` method.
44+
45+
{{< clients-example pipe_trans_tutorial basic_pipe Java-Sync >}}
46+
{{< /clients-example >}}
47+
48+
## Execute a transaction
49+
50+
A transaction works in a similar way to a pipeline. Create a
51+
transaction object with the `multi()`, call command methods
52+
on that object, and then call the transaction object's
53+
`exec()` method to execute it. You can access the results
54+
from commands in the transaction using `Response` objects, as
55+
you would with a pipeline. However, the `exec()` method also
56+
returns a `List<Object>` value that contains all the result
57+
values in the order the commands were executed (see
58+
[Watch keys for changes](#watch-keys-for-changes) below for
59+
an example that uses the results list).
60+
61+
{{< clients-example pipe_trans_tutorial basic_trans Java-Sync >}}
62+
{{< /clients-example >}}
63+
64+
## Watch keys for changes
65+
66+
Redis supports *optimistic locking* to avoid inconsistent updates
67+
to different keys. The basic idea is to watch for changes to any
68+
keys that you use in a transaction while you are are processing the
69+
updates. If the watched keys do change, you must restart the updates
70+
with the latest data from the keys. See
71+
[Transactions]({{< relref "/develop/interact/transactions" >}})
72+
for more information about optimistic locking.
73+
74+
The code below reads a string
75+
that represents a `PATH` variable for a command shell, then appends a new
76+
command path to the string before attempting to write it back. If the watched
77+
key is modified by another client before writing, the transaction aborts.
78+
Note that you should call read-only commands for the watched keys synchronously on
79+
the usual client object (called `jedis` in our examples) but you still call commands
80+
for the transaction on the transaction object.
81+
82+
For production usage, you would generally call code like the following in
83+
a loop to retry it until it succeeds or else report or log the failure.
84+
85+
{{< clients-example pipe_trans_tutorial trans_watch Java-Sync >}}
86+
{{< /clients-example >}}

content/develop/clients/redis-py/transpipe.md

Lines changed: 6 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,8 @@ Note that the command methods for a pipeline always return the original
4141
pipeline object, so you can "chain" several commands together, as the
4242
example below shows:
4343

44-
<!-- Tested examples will replace the inline ones when they are approved.
45-
Markup removed to stop warnings.
46-
47-
clients-example pipe_trans_tutorial basic_pipe Python
48-
/clients-example
49-
-->
50-
```python
51-
import redis
52-
53-
r = redis.Redis(decode_responses=True)
54-
55-
pipe = r.pipeline()
56-
57-
for i in range(5):
58-
pipe.set(f"seat:{i}", f"#{i}")
59-
60-
set_5_result = pipe.execute()
61-
print(set_5_result) # >>> [True, True, True, True, True]
62-
63-
pipe = r.pipeline()
64-
65-
# "Chain" pipeline commands together.
66-
get_3_result = pipe.get("seat:0").get("seat:3").get("seat:4").execute()
67-
print(get_3_result) # >>> ['#0', '#3', '#4']
68-
```
44+
{{< clients-example pipe_trans_tutorial basic_pipe Python >}}
45+
{{< /clients-example >}}
6946

7047
## Execute a transaction
7148

@@ -96,43 +73,8 @@ key is modified by another client before writing, the transaction aborts
9673
with a `WatchError` exception, and the loop executes again for another attempt.
9774
Otherwise, the loop terminates successfully.
9875

99-
<!--
100-
clients-example pipe_trans_tutorial trans_watch Python
101-
/clients-example
102-
-->
103-
```python
104-
r.set("shellpath", "/usr/syscmds/")
105-
106-
with r.pipeline() as pipe:
107-
# Repeat until successful.
108-
while True:
109-
try:
110-
# Watch the key we are about to change.
111-
pipe.watch("shellpath")
112-
113-
# The pipeline executes commands directly (instead of
114-
# buffering them) from immediately after the `watch()`
115-
# call until we begin the transaction.
116-
current_path = pipe.get("shellpath")
117-
new_path = current_path + ":/usr/mycmds/"
118-
119-
# Start the transaction, which will enable buffering
120-
# again for the remaining commands.
121-
pipe.multi()
122-
123-
pipe.set("shellpath", new_path)
124-
125-
pipe.execute()
126-
127-
# The transaction succeeded, so break out of the loop.
128-
break
129-
except redis.WatchError:
130-
# The transaction failed, so continue with the next attempt.
131-
continue
132-
133-
get_path_result = r.get("shellpath")
134-
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
135-
```
76+
{{< clients-example pipe_trans_tutorial trans_watch Python >}}
77+
{{< /clients-example >}}
13678

13779
Because this is a common pattern, the library includes a convenience
13880
method called `transaction()` that handles the code to watch keys,
@@ -144,26 +86,5 @@ using `transaction()`. Note that `transaction()` can't add the `multi()`
14486
call automatically, so you must still place this correctly in your
14587
transaction function.
14688

147-
<!--
148-
clients-example pipe_trans_tutorial watch_conv_method Python
149-
/clients-example
150-
*-->
151-
```python
152-
r.set("shellpath", "/usr/syscmds/")
153-
154-
155-
def watched_sequence(pipe):
156-
current_path = pipe.get("shellpath")
157-
new_path = current_path + ":/usr/mycmds/"
158-
159-
pipe.multi()
160-
161-
pipe.set("shellpath", new_path)
162-
163-
164-
trans_result = r.transaction(watched_sequence, "shellpath")
165-
print(trans_result) # True
166-
167-
get_path_result = r.get("shellpath")
168-
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
169-
```
89+
{{< clients-example pipe_trans_tutorial watch_conv_method Python >}}
90+
{{< /clients-example >}}

content/develop/data-types/probabilistic/bloom-filter.md

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ categories:
1010
- kubernetes
1111
- clients
1212
description: Bloom filters are a probabilistic data structure that checks for presence
13-
of an element in a set
13+
of an item in a set
1414
linkTitle: Bloom filter
1515
stack: true
1616
title: Bloom filter
@@ -19,9 +19,9 @@ weight: 10
1919

2020
A Bloom filter is a probabilistic data structure in Redis Community Edition that enables you to check if an element is present in a set using a very small memory space of a fixed size.
2121

22-
Instead of storing all of the elements in the set, Bloom Filters store only the elements' hashed representation, thus sacrificing some precision. The trade-off is that Bloom Filters are very space-efficient and fast.
22+
Instead of storing all the items in a set, a Bloom Filter stores only the items' hashed representations, thus sacrificing some precision. The trade-off is that Bloom Filters are very space-efficient and fast.
2323

24-
A Bloom filter can guarantee the absence of an element from a set, but it can only give an estimation about its presence. So when it responds that an element is not present in a set (a negative answer), you can be sure that indeed is the case. But one out of every N positive answers will be wrong. Even though it looks unusual at a first glance, this kind of uncertainty still has its place in computer science. There are many cases out there where a negative answer will prevent more costly operations, for example checking if a username has been taken, if a credit card has been reported as stolen, if a user has already seen an ad and much more.
24+
A Bloom filter can guarantee the absence of an item from a set, but it can only give an estimation about its presence. So when it responds that an item is not present in a set (a negative answer), you can be sure that indeed is the case. But one out of every N positive answers will be wrong. Even though it looks unusual at first glance, this kind of uncertainty still has its place in computer science. There are many cases out there where a negative answer will prevent more costly operations, for example checking if a username has been taken, if a credit card has been reported as stolen, if a user has already seen an ad and much more.
2525

2626
## Use cases
2727

@@ -111,11 +111,11 @@ BF.RESERVE {key} {error_rate} {capacity} [EXPANSION expansion] [NONSCALING]
111111
The rate is a decimal value between 0 and 1. For example, for a desired false positive rate of 0.1% (1 in 1000), error_rate should be set to 0.001.
112112

113113
#### 2. Expected capacity (`capacity`)
114-
This is the number of elements you expect having in your filter in total and is trivial when you have a static set but it becomes more challenging when your set grows over time. It's important to get the number right because if you **oversize** - you'll end up wasting memory. If you **undersize**, the filter will fill up and a new one will have to be stacked on top of it (sub-filter stacking). In the cases when a filter consists of multiple sub-filters stacked on top of each other latency for adds stays the same, but the latency for presence checks increases. The reason for this is the way the checks work: a regular check would first be performed on the top (latest) filter and if a negative answer is returned the next one is checked and so on. That's where the added latency comes from.
114+
This is the number of items you expect having in your filter in total and is trivial when you have a static set but it becomes more challenging when your set grows over time. It's important to get the number right because if you **oversize** - you'll end up wasting memory. If you **undersize**, the filter will fill up and a new one will have to be stacked on top of it (sub-filter stacking). In the cases when a filter consists of multiple sub-filters stacked on top of each other latency for adds stays the same, but the latency for presence checks increases. The reason for this is the way the checks work: a regular check would first be performed on the top (latest) filter and if a negative answer is returned the next one is checked and so on. That's where the added latency comes from.
115115

116116
#### 3. Scaling (`EXPANSION`)
117-
Adding an element to a Bloom filter never fails due to the data structure "filling up". Instead the error rate starts to grow. To keep the error close to the one set on filter initialisation - the Bloom filter will auto-scale, meaning when capacity is reached an additional sub-filter will be created.
118-
The size of the new sub-filter is the size of the last sub-filter multiplied by `EXPANSION`. If the number of elements to be stored in the filter is unknown, we recommend that you use an expansion of 2 or more to reduce the number of sub-filters. Otherwise, we recommend that you use an expansion of 1 to reduce memory consumption. The default expansion value is 2.
117+
Adding an item to a Bloom filter never fails due to the data structure "filling up". Instead, the error rate starts to grow. To keep the error close to the one set on filter initialization, the Bloom filter will auto-scale, meaning, when capacity is reached, an additional sub-filter will be created.
118+
The size of the new sub-filter is the size of the last sub-filter multiplied by `EXPANSION`. If the number of items to be stored in the filter is unknown, we recommend that you use an expansion of 2 or more to reduce the number of sub-filters. Otherwise, we recommend that you use an expansion of 1 to reduce memory consumption. The default expansion value is 2.
119119

120120
The filter will keep adding more hash functions for every new sub-filter in order to keep your desired error rate.
121121

@@ -127,26 +127,22 @@ If you know you're not going to scale use the `NONSCALING` flag because that way
127127

128128
### Total size of a Bloom filter
129129
The actual memory used by a Bloom filter is a function of the chosen error rate:
130-
```
131-
bits_per_item = -log(error)/ln(2)
132-
memory = capacity * bits_per_item
133-
134-
memory = capacity * (-log(error)/ln(2))
135-
```
136130

137-
- 1% error rate requires 10.08 bits per item
138-
- 0.1% error rate requires 14.4 bits per item
139-
- 0.01% error rate requires 20.16 bits per item
131+
The optimal number of hash functions is `ceil(-ln(error_rate) / ln(2))`.
132+
133+
The required number of bits per item, given the desired `error_rate` and the optimal number of hash functions, is `-ln(error_rate) / ln(2)^2`. Hence, the required number of bits in the filter is `capacity * -ln(error_rate) / ln(2)^2`.
134+
135+
* **1%** error rate requires 7 hash functions and 9.585 bits per item.
136+
* **0.1%** error rate requires 10 hash functions and 14.378 bits per item.
137+
* **0.01%** error rate requires 14 hash functions and 19.170 bits per item.
140138

141139
Just as a comparison, when using a Redis set for membership testing the memory needed is:
142140

143141
```
144142
memory_with_sets = capacity*(192b + value)
145143
```
146144

147-
For a set of IP addresses, for example, we would have around 40 bytes (320 bits) per element, which is considerably higher than the 20 bits per element we need for a Bloom filter with 0.01% precision.
148-
149-
145+
For a set of IP addresses, for example, we would have around 40 bytes (320 bits) per item - considerably higher than the 19.170 bits we need for a Bloom filter with a 0.01% false positives rate.
150146

151147

152148
## Bloom vs. Cuckoo filters
@@ -159,7 +155,7 @@ Cuckoo filters are quicker on check operations and also allow deletions.
159155

160156
Insertion in a Bloom filter is O(K), where `k` is the number of hash functions.
161157

162-
Checking for an element is O(K) or O(K*n) for stacked filters, where n is the number of stacked filters.
158+
Checking for an item is O(K) or O(K*n) for stacked filters, where n is the number of stacked filters.
163159

164160

165161
## Academic sources

0 commit comments

Comments
 (0)