Skip to content

Commit 029214b

Browse files
author
Julien Ruaux
committed
feat: Added built-in fields (id and score) to resultset columns
1 parent a139f2d commit 029214b

File tree

5 files changed

+107
-13
lines changed

5 files changed

+107
-13
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.redis.trino;
2+
3+
import static com.google.common.collect.ImmutableMap.toImmutableMap;
4+
import static io.trino.spi.type.RealType.REAL;
5+
import static io.trino.spi.type.VarcharType.VARCHAR;
6+
import static java.util.Arrays.stream;
7+
import static java.util.function.Function.identity;
8+
9+
import java.util.Map;
10+
import java.util.Optional;
11+
12+
import com.redis.lettucemod.search.Field;
13+
14+
import io.trino.spi.connector.ColumnMetadata;
15+
import io.trino.spi.type.Type;
16+
17+
enum RediSearchBuiltinField {
18+
19+
ID("_id", VARCHAR, Field.Type.TAG), SCORE("_score", REAL, Field.Type.NUMERIC);
20+
21+
private static final Map<String, RediSearchBuiltinField> COLUMNS_BY_NAME = stream(values())
22+
.collect(toImmutableMap(RediSearchBuiltinField::getName, identity()));
23+
24+
private final String name;
25+
private final Type type;
26+
private final Field.Type fieldType;
27+
28+
RediSearchBuiltinField(String name, Type type, Field.Type fieldType) {
29+
this.name = name;
30+
this.type = type;
31+
this.fieldType = fieldType;
32+
}
33+
34+
public static Optional<RediSearchBuiltinField> of(String name) {
35+
return Optional.ofNullable(COLUMNS_BY_NAME.get(name));
36+
}
37+
38+
public static boolean isBuiltinColumn(String name) {
39+
return COLUMNS_BY_NAME.containsKey(name);
40+
}
41+
42+
public String getName() {
43+
return name;
44+
}
45+
46+
public Type getType() {
47+
return type;
48+
}
49+
50+
public Field.Type getFieldType() {
51+
return fieldType;
52+
}
53+
54+
public ColumnMetadata getMetadata() {
55+
return ColumnMetadata.builder().setName(name).setType(type).setHidden(true).build();
56+
}
57+
58+
public RediSearchColumnHandle getColumnHandle() {
59+
return new RediSearchColumnHandle(name, type, fieldType, true, false);
60+
}
61+
}

src/main/java/com/redis/trino/RediSearchPageSource.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ public class RediSearchPageSource implements ConnectorPageSource {
5858

5959
public RediSearchPageSource(RediSearchSession rediSearchSession, RediSearchTableHandle tableHandle,
6060
List<RediSearchColumnHandle> columns) {
61-
this.columnNames = columns.stream().map(RediSearchColumnHandle::getName).collect(Collectors.toList());
62-
this.columnTypes = columns.stream().map(RediSearchColumnHandle::getType).collect(Collectors.toList());
61+
this.columnNames = columns.stream().map(RediSearchColumnHandle::getName).collect(Collectors.toUnmodifiableList());
62+
this.columnTypes = columns.stream().map(RediSearchColumnHandle::getType).collect(Collectors.toUnmodifiableList());
6363
this.cursor = rediSearchSession.search(tableHandle, columns).iterator();
6464
this.currentDoc = null;
6565
this.pageBuilder = new PageBuilder(columnTypes);
@@ -100,7 +100,8 @@ public Page getNextPage() {
100100
pageBuilder.declarePosition();
101101
for (int column = 0; column < columnTypes.size(); column++) {
102102
BlockBuilder output = pageBuilder.getBlockBuilder(column);
103-
String value = currentDoc.get(columnNames.get(column));
103+
String columnName = columnNames.get(column);
104+
String value = currentValue(columnName);
104105
if (value == null) {
105106
output.appendNull();
106107
} else {
@@ -114,6 +115,18 @@ public Page getNextPage() {
114115
return page;
115116
}
116117

118+
private String currentValue(String columnName) {
119+
if (RediSearchBuiltinField.isBuiltinColumn(columnName)) {
120+
if (RediSearchBuiltinField.ID.getName().equals(columnName)) {
121+
return currentDoc.getId();
122+
}
123+
if (RediSearchBuiltinField.SCORE.getName().equals(columnName)) {
124+
return String.valueOf(currentDoc.getScore());
125+
}
126+
}
127+
return currentDoc.get(columnName);
128+
}
129+
117130
public static JsonGenerator createJsonGenerator(JsonFactory factory, SliceOutput output) throws IOException {
118131
return factory.createGenerator((OutputStream) output);
119132
}

src/main/java/com/redis/trino/RediSearchSession.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -217,25 +217,28 @@ private RediSearchTable loadTableSchema(SchemaTableName schemaTableName) {
217217
throw new TableNotFoundException(schemaTableName, format("Index '%s' not found", index), null);
218218
}
219219
Set<String> fields = new HashSet<>();
220-
ImmutableList.Builder<RediSearchColumnHandle> columnHandles = ImmutableList.builder();
221-
for (Field<String> field : indexInfo.get().getFields()) {
222-
RediSearchColumnHandle column = buildColumnHandle(field);
220+
ImmutableList.Builder<RediSearchColumnHandle> columns = ImmutableList.builder();
221+
for (RediSearchBuiltinField builtinfield : RediSearchBuiltinField.values()) {
222+
fields.add(builtinfield.getName());
223+
columns.add(builtinfield.getColumnHandle());
224+
}
225+
for (Field<String> indexedField : indexInfo.get().getFields()) {
226+
RediSearchColumnHandle column = buildColumnHandle(indexedField);
223227
fields.add(column.getName());
224-
columnHandles.add(column);
228+
columns.add(column);
225229
}
226230
SearchResults<String, String> results = connection.sync().ftSearch(index, "*");
227231
for (Document<String, String> doc : results) {
228-
for (String field : doc.keySet()) {
229-
if (fields.contains(field)) {
232+
for (String docField : doc.keySet()) {
233+
if (fields.contains(docField)) {
230234
continue;
231235
}
232-
columnHandles
233-
.add(new RediSearchColumnHandle(field, VarcharType.VARCHAR, Field.Type.TEXT, false, false));
234-
fields.add(field);
236+
columns.add(new RediSearchColumnHandle(docField, VarcharType.VARCHAR, Field.Type.TEXT, false, false));
237+
fields.add(docField);
235238
}
236239
}
237240
return new RediSearchTable(new RediSearchTableHandle(RediSearchTableHandle.Type.SEARCH, schemaTableName),
238-
columnHandles.build());
241+
columns.build());
239242
}
240243

241244
private Optional<IndexInfo> indexInfo(String index) {

src/main/java/com/redis/trino/RediSearchTranslator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ public Search search(RediSearchTableHandle tableHandle, List<RediSearchColumnHan
226226
String index = index(tableHandle);
227227
String query = queryBuilder.buildQuery(tableHandle.getConstraint(), tableHandle.getWildcards());
228228
Builder<String, String> options = SearchOptions.builder();
229+
options.withScores(true);
229230
options.limit(Limit.offset(0).num(limit(tableHandle)));
230231
options.returnFields(columns.stream().map(RediSearchColumnHandle::getName).toArray(String[]::new));
231232
return Search.builder().index(index).query(query).options(options.build()).build();

src/test/java/com/redis/trino/TestRediSearchConnectorSmokeTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,26 @@ protected QueryRunner createQueryRunner() throws Exception {
109109

110110
@Test
111111
public void testNonIndexedFields() throws IOException {
112+
try {
113+
redisearch.getTestContext().sync().ftDropindexDeleteDocs(Beers.INDEX);
114+
} catch (Exception e) {
115+
// ignore
116+
}
112117
Beers.populateIndex(redisearch.getTestContext().getConnection());
113118
getQueryRunner().execute("select id, last_mod from beers");
114119
}
115120

121+
@Test
122+
public void testBuiltinFields() throws IOException {
123+
try {
124+
redisearch.getTestContext().sync().ftDropindexDeleteDocs(Beers.INDEX);
125+
} catch (Exception e) {
126+
// ignore
127+
}
128+
Beers.populateIndex(redisearch.getTestContext().getConnection());
129+
getQueryRunner().execute("select _id, _score from beers");
130+
}
131+
116132
@SuppressWarnings("unchecked")
117133
@Test
118134
public void testJsonSearch() throws IOException {

0 commit comments

Comments
 (0)