Skip to content

Commit 982a0a5

Browse files
Add Redis Search API surface (FT.CREATE, FT.DROPINDEX, FT.SEARCH)
Signed-off-by: viktoriya.kutsarova <viktoriya.kutsarova@redis.com>
1 parent 9f4d8d4 commit 982a0a5

18 files changed

+1928
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2026-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.connection;
17+
18+
import org.jspecify.annotations.NullUnmarked;
19+
20+
import org.springframework.data.redis.search.DropIndexOptions;
21+
import org.springframework.data.redis.search.IndexDefinition;
22+
import org.springframework.data.redis.search.Schema;
23+
import org.springframework.data.redis.search.SearchOptions;
24+
import org.springframework.data.redis.search.SearchQuery;
25+
import org.springframework.data.redis.search.SearchResult;
26+
27+
/**
28+
* Redis Search commands ({@code FT.*}) operating on a single connection.
29+
* <p>
30+
* These commands are not available in pipeline or transaction mode and will throw an exception if invoked in that context.
31+
*
32+
* @author Viktoriya Kutsarova
33+
* @see <a href="https://redis.io/docs/latest/develop/interact/search-and-query/">Redis Search</a>
34+
*/
35+
@NullUnmarked
36+
public interface RedisSearchCommands {
37+
38+
/**
39+
* Create a new Redis Search index with default options.
40+
*
41+
* @param name index name; must not be {@literal null}.
42+
* @param schema field definitions for the index; must not be {@literal null}.
43+
* @return {@code "OK"} on success.
44+
* @see <a href="https://redis.io/commands/ft.create/">FT.CREATE</a>
45+
*/
46+
default String createIndex(String name, Schema schema) {
47+
return createIndex(name, schema, IndexDefinition.create());
48+
}
49+
50+
/**
51+
* Create a new Redis Search index with the given definition.
52+
*
53+
* @param name index name; must not be {@literal null}.
54+
* @param schema field definitions for the index; must not be {@literal null}.
55+
* @param definition index-level options (data type, prefixes, language, etc.); must not be {@literal null}.
56+
* @return {@code "OK"} on success.
57+
* @see <a href="https://redis.io/commands/ft.create/">FT.CREATE</a>
58+
*/
59+
String createIndex(String name, Schema schema, IndexDefinition definition);
60+
61+
/**
62+
* Drop an existing index without deleting the underlying documents.
63+
*
64+
* @param name index name; must not be {@literal null}.
65+
* @see <a href="https://redis.io/commands/ft.dropindex/">FT.DROPINDEX</a>
66+
*/
67+
default void dropIndex(String name) {
68+
dropIndex(name, DropIndexOptions.create());
69+
}
70+
71+
/**
72+
* Drop an existing index with the given options.
73+
*
74+
* @param name index name; must not be {@literal null}.
75+
* @param options drop options; must not be {@literal null}.
76+
* @see DropIndexOptions#deleteDocuments()
77+
* @see <a href="https://redis.io/commands/ft.dropindex/">FT.DROPINDEX</a>
78+
*/
79+
void dropIndex(String name, DropIndexOptions options);
80+
81+
/**
82+
* Execute a full-text / field-range search against an index using default options.
83+
*
84+
* @param index index name; must not be {@literal null}.
85+
* @param query search query; must not be {@literal null}.
86+
* @return the search result; never {@literal null}.
87+
* @see SearchQuery#of(String)
88+
* @see SearchQuery#all()
89+
* @see <a href="https://redis.io/commands/ft.search/">FT.SEARCH</a>
90+
*/
91+
default SearchResult search(String index, SearchQuery query) {
92+
return search(index, query, SearchOptions.create());
93+
}
94+
95+
/**
96+
* Execute a full-text / field-range search against an index with the given options.
97+
*
98+
* @param index index name; must not be {@literal null}.
99+
* @param query search query; must not be {@literal null}.
100+
* @param options search options (LIMIT, SORTBY, RETURN, etc.); must not be {@literal null}.
101+
* @return the search result; never {@literal null}.
102+
* @see SearchQuery#of(String)
103+
* @see SearchQuery#all()
104+
* @see <a href="https://redis.io/commands/ft.search/">FT.SEARCH</a>
105+
*/
106+
SearchResult search(String index, SearchQuery query, SearchOptions options);
107+
}
108+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2026-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.search;
17+
18+
/**
19+
* Options for the Redis Search {@code FT.DROPINDEX} command.
20+
* <p>
21+
* Use the fluent factory method {@link #create()} to build an instance:
22+
* <pre class="code">
23+
* // Drop index only, keep documents
24+
* DropIndexOptions.create()
25+
*
26+
* // Drop index and delete all indexed documents
27+
* DropIndexOptions.create().deleteDocuments()
28+
* </pre>
29+
*
30+
* @author Viktoriya Kutsarova
31+
* @see org.springframework.data.redis.connection.RedisSearchCommands#dropIndex(String, DropIndexOptions)
32+
* @see <a href="https://redis.io/commands/ft.dropindex/">FT.DROPINDEX</a>
33+
*/
34+
public class DropIndexOptions {
35+
36+
private boolean deleteDocuments;
37+
38+
private DropIndexOptions() {}
39+
40+
/**
41+
* Create a new {@link DropIndexOptions} instance.
42+
*/
43+
public static DropIndexOptions create() {
44+
return new DropIndexOptions();
45+
}
46+
47+
/**
48+
* Delete all documents indexed by this index ({@code DD} flag).
49+
* <p>
50+
* When set, all documents that were indexed by this index will be deleted
51+
* along with the index itself. Use with caution as this operation is irreversible.
52+
*/
53+
public DropIndexOptions deleteDocuments() {
54+
this.deleteDocuments = true;
55+
return this;
56+
}
57+
58+
/**
59+
* Return whether indexed documents should be deleted along with the index.
60+
*/
61+
public boolean isDeleteDocuments() {
62+
return deleteDocuments;
63+
}
64+
}
65+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2026-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.search;
17+
18+
/**
19+
* A geographic {@link SchemaField} for radius-based queries on longitude/latitude pairs
20+
* stored as comma-separated strings.
21+
* <p>
22+
* Create instances via {@link SchemaField#geo(String)}.
23+
*
24+
* @author Viktoriya Kutsarova
25+
* @see SchemaField#geo(String)
26+
* @see <a href="https://redis.io/commands/ft.create/">FT.CREATE — GEO field options</a>
27+
*/
28+
public final class GeoField extends SchemaField {
29+
30+
private boolean sortable;
31+
private boolean unnormalized;
32+
33+
GeoField(String name) {
34+
super(name);
35+
}
36+
37+
/**
38+
* Enable low-latency sorting on this field ({@code SORTABLE}).
39+
*/
40+
public GeoField sortable() {
41+
this.sortable = true;
42+
return this;
43+
}
44+
45+
/**
46+
* Enable sortable without normalization ({@code SORTABLE UNF}).
47+
* Preserves the original case and diacritics for sorting.
48+
*/
49+
public GeoField sortableUnnormalized() {
50+
this.sortable = true;
51+
this.unnormalized = true;
52+
return this;
53+
}
54+
55+
public boolean isSortable() {
56+
return sortable;
57+
}
58+
59+
public boolean isUnnormalized() {
60+
return unnormalized;
61+
}
62+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2026-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.search;
17+
18+
/**
19+
* The Redis data structure type that an index operates on.
20+
*
21+
* @author Viktoriya Kutsarova
22+
*/
23+
public enum IndexDataType {
24+
25+
/**
26+
* Index Redis Hash documents.
27+
*/
28+
HASH,
29+
30+
/**
31+
* Index Redis JSON documents (requires RedisJSON module).
32+
*/
33+
JSON
34+
}

0 commit comments

Comments
 (0)