Skip to content

Commit a7941bd

Browse files
bsboddenclaude
andcommitted
feat(schema): add UNF/NOINDEX field attributes (#374)
Add support for UNF (un-normalized form) and NOINDEX attributes for schema field classes, following Python RedisVL PR #386. Features: - TextField: Add UNF support via Jedis sortableUNF() - NumericField: Add UNF flag (stored but limited by Jedis) - NOINDEX: Already supported via indexed=false - Comprehensive unit tests (16 tests) - Maintains backward compatibility Key behaviors: - UNF only applies when sortable=true - UNF preserves original character case for sorting - NOINDEX prevents indexing, field still sortable/retrievable - TextField & NumericField support both UNF and NOINDEX - TagField & GeoField support NOINDEX only Limitations: - Jedis NumericField doesn't have sortableUNF() yet - Filed TODO to request Jedis enhancement Python Reference: redis/redis-vl-python#386 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent e1053e0 commit a7941bd

File tree

3 files changed

+374
-7
lines changed

3 files changed

+374
-7
lines changed

core/src/main/java/com/redis/vl/schema/NumericField.java

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,22 @@
1010
@Getter
1111
public class NumericField extends BaseField {
1212

13+
/** Un-normalized form - disable normalization for sorting (only applies when sortable=true) */
14+
private final boolean unf;
15+
1316
/**
1417
* Create a NumericField with just a name.
1518
*
1619
* @param name The field name
1720
*/
1821
public NumericField(String name) {
19-
super(name);
22+
this(name, null, true, false, false);
2023
}
2124

2225
/** Create a NumericField with all properties */
23-
private NumericField(String name, String alias, Boolean indexed, Boolean sortable) {
26+
private NumericField(String name, String alias, Boolean indexed, Boolean sortable, Boolean unf) {
2427
super(name, alias, indexed != null ? indexed : true, sortable != null ? sortable : false);
28+
this.unf = unf != null ? unf : false;
2529
}
2630

2731
/**
@@ -59,6 +63,9 @@ public SchemaField toJedisSchemaField() {
5963

6064
if (sortable) {
6165
jedisField.sortable();
66+
// NOTE: Jedis NumericField doesn't support sortableUNF() yet
67+
// The unf flag is stored in this wrapper but cannot be passed to Redis via Jedis
68+
// TODO: File issue with Jedis to add sortableUNF() support for NumericField
6269
}
6370

6471
if (!indexed) {
@@ -74,6 +81,7 @@ public static class NumericFieldBuilder {
7481
private String alias;
7582
private Boolean indexed;
7683
private Boolean sortable;
84+
private Boolean unf;
7785

7886
private NumericFieldBuilder(String name) {
7987
this.name = name;
@@ -144,6 +152,39 @@ public NumericFieldBuilder sortable() {
144152
return this;
145153
}
146154

155+
/**
156+
* Set whether to use un-normalized form for sorting
157+
*
158+
* <p>UNF disables normalization when sorting, preserving original values. Only applies when
159+
* sortable=true.
160+
*
161+
* <p>NOTE: Jedis doesn't support sortableUNF() for NumericField yet, so this flag is stored but
162+
* not passed to Redis.
163+
*
164+
* @param unf True to disable normalization for sorting
165+
* @return This builder for chaining
166+
*/
167+
public NumericFieldBuilder unf(boolean unf) {
168+
this.unf = unf;
169+
return this;
170+
}
171+
172+
/**
173+
* Use un-normalized form for sorting (equivalent to unf(true))
174+
*
175+
* <p>UNF disables normalization when sorting, preserving original values. Only applies when
176+
* sortable=true.
177+
*
178+
* <p>NOTE: Jedis doesn't support sortableUNF() for NumericField yet, so this flag is stored but
179+
* not passed to Redis.
180+
*
181+
* @return This builder for chaining
182+
*/
183+
public NumericFieldBuilder unf() {
184+
this.unf = true;
185+
return this;
186+
}
187+
147188
/**
148189
* Build the NumericField instance.
149190
*
@@ -154,7 +195,7 @@ public NumericField build() {
154195
if (name == null || name.trim().isEmpty()) {
155196
throw new IllegalArgumentException("Field name cannot be null or empty");
156197
}
157-
return new NumericField(name, alias, indexed, sortable);
198+
return new NumericField(name, alias, indexed, sortable, unf);
158199
}
159200
}
160201
}

core/src/main/java/com/redis/vl/schema/TextField.java

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@ public class TextField extends BaseField {
2323
@JsonProperty("phonetic")
2424
private final String phonetic;
2525

26+
/** Un-normalized form - disable normalization for sorting (only applies when sortable=true) */
27+
@JsonProperty("unf")
28+
private final boolean unf;
29+
2630
/**
2731
* Create a TextField with just a name
2832
*
2933
* @param name Field name
3034
*/
3135
public TextField(String name) {
32-
this(name, null, true, false, 1.0, false, null);
36+
this(name, null, true, false, 1.0, false, null, false);
3337
}
3438

3539
/** Create a TextField with all properties */
@@ -40,11 +44,13 @@ private TextField(
4044
Boolean sortable,
4145
Double weight,
4246
Boolean noStem,
43-
String phonetic) {
47+
String phonetic,
48+
Boolean unf) {
4449
super(name, alias, indexed != null ? indexed : true, sortable != null ? sortable : false);
4550
this.weight = weight != null ? weight : 1.0;
4651
this.noStem = noStem != null ? noStem : false;
4752
this.phonetic = phonetic;
53+
this.unf = unf != null ? unf : false;
4854
}
4955

5056
/**
@@ -80,7 +86,11 @@ public SchemaField toJedisSchemaField() {
8086
jedisField.as(alias);
8187
}
8288

83-
if (sortable) {
89+
// Handle sortable with UNF support
90+
// UNF only applies when sortable=true
91+
if (sortable && unf) {
92+
jedisField.sortableUNF();
93+
} else if (sortable) {
8494
jedisField.sortable();
8595
}
8696

@@ -112,6 +122,7 @@ public static class TextFieldBuilder {
112122
private Double weight;
113123
private Boolean noStem;
114124
private String phonetic;
125+
private Boolean unf;
115126

116127
private TextFieldBuilder(String name) {
117128
this.name = name;
@@ -247,6 +258,33 @@ public TextFieldBuilder withPhonetic(String phonetic) {
247258
return this;
248259
}
249260

261+
/**
262+
* Set whether to use un-normalized form for sorting
263+
*
264+
* <p>UNF disables normalization when sorting, preserving original character case. Only applies
265+
* when sortable=true.
266+
*
267+
* @param unf True to disable normalization for sorting
268+
* @return This builder
269+
*/
270+
public TextFieldBuilder unf(boolean unf) {
271+
this.unf = unf;
272+
return this;
273+
}
274+
275+
/**
276+
* Use un-normalized form for sorting (equivalent to unf(true))
277+
*
278+
* <p>UNF disables normalization when sorting, preserving original character case. Only applies
279+
* when sortable=true.
280+
*
281+
* @return This builder
282+
*/
283+
public TextFieldBuilder unf() {
284+
this.unf = true;
285+
return this;
286+
}
287+
250288
/**
251289
* Build the TextField
252290
*
@@ -256,7 +294,7 @@ public TextField build() {
256294
if (name == null || name.trim().isEmpty()) {
257295
throw new IllegalArgumentException("Field name cannot be null or empty");
258296
}
259-
return new TextField(name, alias, indexed, sortable, weight, noStem, phonetic);
297+
return new TextField(name, alias, indexed, sortable, weight, noStem, phonetic, unf);
260298
}
261299
}
262300
}

0 commit comments

Comments
 (0)