Skip to content

Commit 5f3ebc2

Browse files
Merge pull request redis-developer#608 from wjohnsto/master
Vector Search Tutorial
2 parents f86a708 + a3ca576 commit 5f3ebc2

File tree

20 files changed

+1015
-124
lines changed

20 files changed

+1015
-124
lines changed

docs/develop/java/getting-started/index.md

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,7 @@ Find tutorials, examples and technical articles that will help you to develop wi
1414

1515
## Getting Started
1616

17-
Java community has built many client libraries that you can find [here](https://redis.io/clients#java). For your first steps with Java and Redis, this article will show how to use the two main libraries: [Jedis](https://github.com/redis/jedis) and [Lettuce](https://lettuce.io/).
18-
19-
The blog post “[Jedis vs. Lettuce: An Exploration](https://redis.com/blog/jedis-vs-lettuce-an-exploration/)” will help you to select the best for your application; keeping in mind that both are available in Spring & SpringBoot framework.
20-
21-
<Tabs
22-
defaultValue="jedis"
23-
values={[
24-
{label: 'Jedis', value: 'jedis'},
25-
{label: 'Lettuce', value: 'lettuce'},
26-
]}>
27-
<TabItem value="jedis">
17+
Java community has built many client libraries that you can find [here](https://redis.io/clients#java). For your first steps with Java and Redis, this article will show how to use [Jedis](https://github.com/redis/jedis), the supported Redis client for Java.
2818

2919
Redis is an open source, in-memory, key-value data store most commonly used as a primary database, cache, message broker, and queue. Redis delivers sub-millisecond response times, enabling fast and powerful real-time applications in industries such as gaming, fintech, ad-tech, social media, healthcare, and IoT.
3020

@@ -106,53 +96,6 @@ Once you have access to the connection pool you can now get a Jedis instance and
10696

10797
Find more information about Java & Redis connections in the "[Redis Connect](https://github.com/redis-developer/redis-connect/tree/master/java/jedis)".
10898

109-
</TabItem>
110-
<TabItem value="lettuce">
111-
112-
## Using Lettuce
113-
114-
### Step 1. Add dependencies Jedis dependency to your Maven (or Gradle) project file:
115-
116-
```xml
117-
<dependency>
118-
<groupId>io.lettuce</groupId>
119-
<artifactId>lettuce-core</artifactId>a
120-
<version>6.0.1.RELEASE</version>
121-
</dependency>
122-
```
123-
124-
### Step 2. Import the Jedis classes
125-
126-
```java
127-
import io.lettuce.core.RedisClient;
128-
import io.lettuce.core.api.StatefulRedisConnection;
129-
import io.lettuce.core.api.sync.RedisCommands;
130-
```
131-
132-
### Step 3. Write your application code
133-
134-
```java
135-
RedisClient redisClient = RedisClient.create("redis://localhost:6379/");
136-
StatefulRedisConnection<String, String> connection = redisClient.connect();
137-
RedisCommands<String, String> syncCommands = connection.sync();
138-
139-
syncCommands.set("mykey", "Hello from Lettuce!");
140-
String value = syncCommands.get("mykey");
141-
System.out.println( value );
142-
143-
syncCommands.zadd("vehicles", 0, "car");
144-
syncCommands.zadd("vehicles", 0, "bike");
145-
List<String> vehicles = syncCommands.zrange("vehicles", 0, -1);
146-
System.out.println( vehicles );
147-
148-
connection.close();
149-
redisClient.shutdown();
150-
```
151-
152-
Find more information about Java & Redis connections in the "[Redis Connect](https://github.com/redis-developer/redis-connect/tree/master/java/lettuce)".
153-
</TabItem>
154-
</Tabs>
155-
15699
### Redis Launchpad
157100

158101
Redis Launchpad is like an “App Store” for Redis sample apps. You can easily find apps for your preferred frameworks and languages.
@@ -248,12 +191,6 @@ As developer you can use the Java client library directly in your application, o
248191

249192
### More developer resources
250193

251-
<div class="row">
252-
253-
<div class="col">
254-
255-
#### Sample Code
256-
257194
**[Brewdis - Product Catalog (Spring)](https://github.com/redis-developer/brewdis)**
258195
See how to use Redis and Spring to build a product catalog with streams, hashes and Search
259196

@@ -263,27 +200,6 @@ See how to use Spring to create multiple producer and consumers with Redis Strea
263200
**[Rate Limiting with Vert.x](https://github.com/redis-developer/vertx-rate-limiting-redis)**
264201
See how to use Redis Sorted Set with Vert.x to build a rate limiting service.
265202

266-
**[Redis Java Samples with Lettuce](https://github.com/redis-developer/vertx-rate-limiting-redis)**
267-
Run Redis Commands from Lettuce
268-
269-
</div>
270-
<div class="col col--1">
271-
</div>
272-
273-
<div class="col">
274-
275-
#### Technical Articles
276-
277-
**[Getting Started with Redis Streams and Java (Lettuce)](https://redis.com/blog/getting-started-with-redis-streams-and-java/)**
278-
279-
**[Jedis vs. Lettuce: An Exploration](https://redis.com/blog/jedis-vs-lettuce-an-exploration/)**
280-
281-
</div>
282-
283-
</div>
284-
285-
---
286-
287203
### Redis University
288204

289205
### [Redis for Java Developers](https://university.redis.com/courses/ru102j/)
@@ -294,7 +210,6 @@ Redis for Java Developers teaches you how to build robust Redis client applicati
294210
<iframe width="560" height="315" src="https://www.youtube.com/embed/CmQMdJefTjc" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
295211
</div>
296212

297-
##
298213

299214
<div>
300215
<a href="https://launchpad.redis.com" target="_blank" rel="noopener" className="link"> <img src="/img/launchpad.png" className="thumb" loading="lazy" alt="Redis Launchpad" /></a>

docs/develop/java/spring/rate-limiting/fixed-window/index-fixed-window-reactive-gears.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ sidebar_label: Atomicity with Gears
55
slug: /develop/java/spring/rate-limiting/fixed-window/reactive-gears
66
---
77

8+
:::warning LETTUCE
9+
10+
This tutorial uses Lettuce, which is an unsupported Redis library. For production applications, we recommend using [<u>**Jedis**</u>](https://github.com/redis/jedis)
11+
12+
:::
13+
814
## Improving atomicity and performance with RedisGears
915

1016
### What is RedisGears?

docs/develop/java/spring/redis-and-spring-course/lesson_7/index-lesson_7.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ slug: /develop/java/redis-and-spring-course/lesson_7
66
authors: [bsb]
77
---
88

9+
:::warning LETTUCE
10+
11+
This tutorial uses Lettuce, which is an unsupported Redis library. For production applications, we recommend using [<u>**Jedis**</u>](https://github.com/redis/jedis)
12+
13+
:::
14+
915
import Authors from '@theme/Authors';
1016

1117
<Authors frontMatter={frontMatter} />

docs/explore/redisinsight/streams/index-streams.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Redis Streams lets you build “Kafka-like” applications, which can:
2020

2121
In addition, Redis Streams has the concept of a consumer group. Redis Streams consumer groups, like the similar concept in [Apache Kafka](https://kafka.apache.org/), allows client applications to consume messages in a distributed fashion (multiple clients), making it easy to scale and create highly available systems.
2222

23-
Let’s dive under the covers and see [Redis Streams](https://redis.io/topics/streams-intro) through the lens of RedisInsight. You will see how to use the [Lettuce Java client](https://developer.redis.com/develop/java/#using-lettuce) to publish and consume messages using consumer group.This is the first basic example that uses a single consumer.
23+
Let’s dive under the covers and see [Redis Streams](https://redis.io/topics/streams-intro) through the lens of RedisInsight. You will see how to use the Redis to publish and consume messages using a consumer group. This is the first basic example that uses a single consumer.
2424

2525
## Prerequisite:
2626

docs/howtos/antipatterns/index-antipatterns.mdx

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,60 +39,33 @@ Let us look at the redis-py that uses a connection pool to manage connections to
3939

4040
[Learn more about redis-py](/develop/python/)
4141

42-
### Example #2 - Lettuce
43-
44-
Lettuce provides generic connection pool support.Lettuce connections are designed to be thread-safe so one connection can be shared amongst multiple threads and Lettuce connections auto-reconnection by default. While connection pooling is not necessary in most cases it can be helpful in certain use cases. Lettuce provides generic connection pooling support.
45-
46-
```java
47-
RedisClient client = RedisClient.create(RedisURI.create(host, port));
48-
49-
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
50-
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
51-
52-
// executing work
53-
try (StatefulRedisConnection<String, String> connection = pool.borrowObject()) {
54-
55-
RedisCommands<String, String> commands = connection.sync();
56-
commands.multi();
57-
commands.set("key", "value");
58-
commands.set("key2", "value2");
59-
commands.exec();
60-
}
61-
62-
// terminating
63-
pool.close();
64-
client.shutdown();
65-
```
66-
67-
[Learn more about Lettuce](/develop/java/?s=lettuce)
68-
69-
### 3. Connecting directly to Redis instances
42+
### 2. Connecting directly to Redis instances
7043

7144
With a large number of clients, a reconnect flood will be able to simply overwhelm a single threaded Redis process and force a failover. Hence, it is recommended that you should use the right tool that allows you to reduce the number of open connections to your Redis server.
7245

7346
[Redis Enterprise DMC proxy](https://docs.redis.com/latest/rs/administering/designing-production/networking/multiple-active-proxy/) allows you to reduce the number of connections to your cache server by acting as a proxy. There are other 3rd party tool like [Twemproxy](https://github.com/twitter/twemproxy). It is a fast and lightweight proxy server that allows you to reduce the number of open connections to your Redis server. It was built primarily to reduce the number of connections to the caching servers on the backend. This, together with protocol pipelining and sharding enables you to horizontally scale your distributed caching architecture.
7447

75-
### 4. More than one secondary shard (Redis OSS)
48+
### 3. More than one secondary shard (Redis OSS)
7649

7750
Redis OSS uses a shard-based quorum. It's advised to use at least 3 copies of the data (2 replica shards per master shard) in order to be protected from split-brain situations. In nutshell, Redis OSS solves the quorum challenge by having an odd number of shards (primary + 2 replicas).
7851

7952
Redis Enterprise solves the quorum challenge with an odd number of nodes. Redis Enterprise avoids a split-brain situation with only 2 copies of the data, which is more cost-efficient. In addition, the so-called ‘quorum-only node' can be used to bring a cluster up to an odd number of nodes if an additional, not necessary data node would be too expensive.
8053

81-
### 5. Performing single operation
54+
### 4. Performing single operation
8255

8356
Performing several operations serially increases connection overhead. Instead, use [Redis Pipelining](https://redis.io/topics/pipelining). Pipelining is the process of sending multiple messages down the pipe without waiting on the reply from each - and (typically) processing the replies later when they come in.
8457

8558
Pipelining is completely a client side implementation. It is aimed at solving response latency issues in high network latency environments. So, the lesser the amount of time spent over the network in sending commands and reading responses, the better. This is effectively achieved by buffering. The client may (or may not) buffer the commands at the TCP stack (as mentioned in other answers) before they are sent to the server. Once they are sent to the server, the server executes them and buffers them on the server side. The benefit of the pipelining is a drastically improved protocol performance. The speedup gained by pipelining ranges from a factor of five for connections to localhost up to a factor of at least one hundred over slower internet connections.
8659

87-
### 6. Caching keys without TTL
60+
### 5. Caching keys without TTL
8861

8962
Redis functions primarily as a key-value store. It is possible to set timeout values on these keys. Said that, a timeout expiration automatically deletes the key. Additionally, when we use commands that delete or overwrite the contents of the key, it will clear the timeout. Redis TTL command is used to get the remaining time of the key expiry in seconds. TTL returns the remaining time to live of a key that has a timeout. This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset.Keys will accumulate and end up being evicted. Hence, it is recommended to set TTLs on all caching keys.
9063

91-
### 7. Endless Redis Replication Loop
64+
### 6. Endless Redis Replication Loop
9265

9366
When attempting to replicate a very large active database over a slow or saturated link, replication never finishes due to the continuous updates. Hence, it is recommended to tune the slave and client buffers to allow for slower replication. Check out [this detailed blog](https://redis.com/blog/the-endless-redis-replication-loop-what-why-and-how-to-solve-it/).
9467

95-
### 8. Hot Keys
68+
### 7. Hot Keys
9669

9770
Redis can easily become the core of your app’s operational data, holding valuable and frequently accessed information. However, if you centralize the access down to a few pieces of data accessed constantly, you create what is known as a hot-key problem. In a Redis cluster, the key is actually what determines where in the cluster that data is stored. The data is stored in one single, primary location based off of hashing that key. So, when you access a single key over and over again, you’re actually accessing a single node/shard over and over again. Let’s put it another way—if you have a cluster of 99 nodes and you have a single key that gets a million requests in a second, all million of those requests will be going to a single node, not spread across the other 98 nodes.
9871

@@ -104,7 +77,7 @@ Redis even provides tools to find where your hot keys are located. Use redis-cli
10477

10578
When possible, the best defence is to avoid the development pattern that is creating the situation. Writing the data to multiple keys that reside in different shards will allow you to access the same data more frequently. In nutshell, having specific keys that are accessed with every client operation. Hence, it's recommended to shard out hot keys using hashing algorithms. You can set policy to LFU and run redis-cli --hotkeys to determine.
10679

107-
### 9. Using Keys command
80+
### 8. Using Keys command
10881

10982
In Redis, the KEYS command can be used to perform exhaustive pattern matching on all stored keys. This is not advisable, as running this on an instance with a large number of keys could take a long time to complete, and will slow down the Redis instance in the process. In the relational world, this is equivalent to running an unbound query (SELECT...FROM without a WHERE clause). Execute this type of operation with care, and take necessary measures to ensure that your tenants are not performing a KEYS operation from within their application code. Use SCAN, which spreads the iteration over many calls, not tying up your whole server at one time.
11083

@@ -115,17 +88,17 @@ Scaning keyspace by keyname is an extremely slow operation and will run O(N) wit
11588
2SQL: SELECT * FROM orders WHERE make=ford AND model=explorer"
11689
```
11790
118-
### 10. Running Ephemeral Redis as a primary database
91+
### 9. Running Ephemeral Redis as a primary database
11992
12093
Redis is often used as a primary storage engine for applications. Unlike using Redis as a cache, using Redis as a primary database requires two extra features to be effective. Any primary database should really be highly available. If a cache goes down, then generally your application is in a brown-out state. If a primary database goes down, your application also goes down. Similarly, if a cache goes down and you restart it empty, that’s no big deal. For a primary database, though, that’s a huge deal. Redis can handle these situations easily, but they generally require a different configuration than running as a cache. Redis as a primary database is great, but you’ve got to support it by turning on the right features.
12194
12295
With Redis open source, you need to set up Redis Sentinel for high availability. In Redis Enterprise, it’s a core feature that you just need to turn on when creating the database. As for durability, both Redis Enterprise and open source Redis provide durability through AOF or snapshotting so your instance(s) start back up the way you left them.
12396
124-
### 11. Storing JSON blobs in a string
97+
### 10. Storing JSON blobs in a string
12598
12699
Microservices written in several languages may not marshal/unmarshal JSON in a consistent manner. Application logic will be required to lock/watch a key for atomic updates. JSON manipulation is often a very compute costly operation. Hence, it is recommended to use HASH data structure and also Redis JSON.
127100
128-
### 12. Translating a table or JSON to a HASH without considering query pattern
101+
### 11. Translating a table or JSON to a HASH without considering query pattern
129102
130103
The only query mechanism is a SCAN which requires reading the data structure and limits filtering to the MATCH directive. It is recommended to store the table or JSON as a string. Break out the indexes into reverse indexes using a SET or SORTED SET and point back to the key for the string.
131104
Using SELECT command and multiple databases inside one Redis instance
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Sample data
2+
const products = [
3+
{
4+
name: 'Puma Men Race Black Watch',
5+
price: 150,
6+
quality: 5,
7+
popularity: 8,
8+
},
9+
{
10+
name: 'Puma Men Top Fluctuation Red Black Watch',
11+
price: 180,
12+
quality: 7,
13+
popularity: 6,
14+
},
15+
{
16+
name: 'Inkfruit Women Behind Cream Tshirt',
17+
price: 5,
18+
quality: 9,
19+
popularity: 7,
20+
},
21+
];
22+
23+
const dataWithAttributes = products.map((product) => ({
24+
x: product.price,
25+
y: product.quality,
26+
label: product.name,
27+
}));
28+
29+
const product1Point = { x: products[0].price, y: products[0].quality };
30+
const product2Point = { x: products[1].price, y: products[1].quality };
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-return */
2+
/* eslint-disable @typescript-eslint/no-unsafe-call */
3+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
4+
5+
const ctxCosine = document
6+
.getElementById('productChartCosine')
7+
.getContext('2d');
8+
9+
function cosineSimilarity(point1, point2) {
10+
let dotProduct = point1.x * point2.x + point1.y * point2.y;
11+
let magnitudePoint1 = Math.sqrt(
12+
Math.pow(point1.x, 2) + Math.pow(point1.y, 2),
13+
);
14+
let magnitudePoint2 = Math.sqrt(
15+
Math.pow(point2.x, 2) + Math.pow(point2.y, 2),
16+
);
17+
return dotProduct / (magnitudePoint1 * magnitudePoint2);
18+
}
19+
20+
const cosineSim = cosineSimilarity(product1Point, product2Point);
21+
22+
const scatterChartCosine = new Chart(ctxCosine, {
23+
type: 'scatter',
24+
data: {
25+
datasets: [
26+
{
27+
label: 'Products',
28+
data: dataWithAttributes,
29+
pointBackgroundColor: ['black', 'red', 'bisque'],
30+
pointRadius: 5,
31+
},
32+
{
33+
label: 'Vector for Product-1',
34+
data: [{ x: 0, y: 0 }, product1Point],
35+
showLine: true,
36+
fill: false,
37+
borderColor: 'black',
38+
pointRadius: [0, 5],
39+
lineTension: 0,
40+
},
41+
{
42+
label: 'Vector for Product-2',
43+
data: [{ x: 0, y: 0 }, product2Point],
44+
showLine: true,
45+
fill: false,
46+
borderColor: 'red',
47+
pointRadius: [0, 5],
48+
lineTension: 0,
49+
},
50+
],
51+
},
52+
options: {
53+
responsive: true,
54+
plugins: {
55+
legend: {
56+
position: 'top',
57+
},
58+
title: {
59+
display: true,
60+
text: `Cosine Similarity between Product-1 and Product-2 is ${cosineSim}`,
61+
},
62+
},
63+
scales: {
64+
x: {
65+
type: 'linear',
66+
position: 'bottom',
67+
title: {
68+
display: true,
69+
text: 'Price ($)',
70+
},
71+
ticks: {
72+
beginAtZero: true,
73+
},
74+
min: 0, // Ensure it starts from 0
75+
},
76+
y: {
77+
title: {
78+
display: true,
79+
text: 'Quality (1-10)',
80+
},
81+
ticks: {
82+
beginAtZero: true,
83+
},
84+
min: 0, // Ensure it starts from 0
85+
},
86+
},
87+
tooltips: {
88+
callbacks: {
89+
title: function (tooltipItem, data) {
90+
return data.datasets[0].data[tooltipItem[0].index].label;
91+
},
92+
},
93+
},
94+
},
95+
});

0 commit comments

Comments
 (0)