or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-operations.mdindex.mdindexing.mdquerying-views.mdserialization.mdstorage-implementations.mdtype-information.md

indexing.mddocs/

0

# Indexing

1

2

Automatic index creation and management using field and method annotations for efficient data access. The indexing system enables fast queries and sorting without loading all data into memory.

3

4

## Capabilities

5

6

### KVIndex Annotation

7

8

Marks fields or methods for indexing in the store, enabling efficient queries and sorted iteration.

9

10

```java { .api }

11

/**

12

* Tags a field to be indexed when storing an object.

13

*

14

* Types are required to have a natural index that uniquely identifies instances in the store.

15

* The default value of the annotation identifies the natural index for the type.

16

*

17

* Indexes allow for more efficient sorting of data read from the store. By annotating a field or

18

* "getter" method with this annotation, an index will be created that will provide sorting based on

19

* the string value of that field.

20

*

21

* Note that creating indices means more space will be needed, and maintenance operations like

22

* updating or deleting a value will become more expensive.

23

*

24

* Indices are restricted to String, integral types (byte, short, int, long, boolean), and arrays

25

* of those values.

26

*/

27

@Retention(RetentionPolicy.RUNTIME)

28

@Target({ElementType.FIELD, ElementType.METHOD})

29

public @interface KVIndex {

30

/**

31

* The name of the index to be created for the annotated entity. Must be unique within

32

* the class. Index names are not allowed to start with an underscore (that's reserved for

33

* internal use). The default value is the natural index name (which is always a copy index

34

* regardless of the annotation's values).

35

*/

36

String value() default NATURAL_INDEX_NAME;

37

38

/**

39

* The name of the parent index of this index. By default there is no parent index, so the

40

* generated data can be retrieved without having to provide a parent value.

41

*

42

* If a parent index is defined, iterating over the data using the index will require providing

43

* a single value for the parent index. This serves as a rudimentary way to provide relationships

44

* between entities in the store.

45

*/

46

String parent() default "";

47

48

/**

49

* Whether to copy the instance's data to the index, instead of just storing a pointer to the

50

* data. The default behavior is to just store a reference; that saves disk space but is slower

51

* to read, since there's a level of indirection.

52

*/

53

boolean copy() default false;

54

}

55

56

/**

57

* Constant for the natural index name used internally by the KVStore system.

58

*/

59

String NATURAL_INDEX_NAME = "__main__";

60

```

61

62

### Basic Field Indexing

63

64

Annotate fields to create indices for efficient querying and sorting.

65

66

**Usage Examples:**

67

68

```java

69

public class Person {

70

@KVIndex // Natural index (required) - uniquely identifies the object

71

public String id;

72

73

@KVIndex("name") // Create an index on the name field

74

public String name;

75

76

@KVIndex("age") // Create an index on the age field

77

public int age;

78

79

@KVIndex("active") // Create an index on the active field

80

public boolean active;

81

82

public Person(String id, String name, int age, boolean active) {

83

this.id = id;

84

this.name = name;

85

this.age = age;

86

this.active = active;

87

}

88

}

89

90

// Usage with the indexed class

91

KVStore store = new InMemoryStore();

92

93

// Write data

94

store.write(new Person("p1", "Alice", 30, true));

95

store.write(new Person("p2", "Bob", 25, false));

96

store.write(new Person("p3", "Charlie", 35, true));

97

98

// Query by name index

99

for (Person p : store.view(Person.class).index("name").first("Alice").last("Bob")) {

100

System.out.println(p.name);

101

}

102

103

// Query by age index

104

for (Person p : store.view(Person.class).index("age").first(25).last(30)) {

105

System.out.println(p.name + " is " + p.age);

106

}

107

```

108

109

### Method-Based Indexing

110

111

Annotate getter methods to create indices based on computed values.

112

113

**Usage Examples:**

114

115

```java

116

public class Employee {

117

@KVIndex

118

public String employeeId;

119

120

public String firstName;

121

public String lastName;

122

public Date birthDate;

123

124

@KVIndex("fullName")

125

public String getFullName() {

126

return firstName + " " + lastName;

127

}

128

129

@KVIndex("birthYear")

130

public int getBirthYear() {

131

return birthDate.getYear() + 1900; // Date.getYear() returns year - 1900

132

}

133

134

@KVIndex("displayName")

135

public String getDisplayName() {

136

return lastName + ", " + firstName;

137

}

138

}

139

140

// Usage

141

Employee emp = new Employee();

142

emp.employeeId = "emp123";

143

emp.firstName = "John";

144

emp.lastName = "Doe";

145

emp.birthDate = new Date(85, 5, 15); // June 15, 1985

146

147

store.write(emp);

148

149

// Query by computed fullName index

150

for (Employee e : store.view(Employee.class).index("fullName").first("John Doe")) {

151

System.out.println("Found: " + e.getDisplayName());

152

}

153

154

// Query by computed birthYear index

155

for (Employee e : store.view(Employee.class).index("birthYear").first(1985).last(1990)) {

156

System.out.println(e.getFullName() + " born in " + e.getBirthYear());

157

}

158

```

159

160

### Hierarchical Indices (Parent-Child Relationships)

161

162

Create parent-child index relationships for hierarchical data structures.

163

164

**Usage Examples:**

165

166

```java

167

public class Task {

168

@KVIndex

169

public String taskId;

170

171

@KVIndex("projectId") // Parent index

172

public String projectId;

173

174

@KVIndex(value = "priority", parent = "projectId") // Child index with parent

175

public String priority;

176

177

@KVIndex(value = "status", parent = "projectId") // Another child index

178

public String status;

179

180

public String title;

181

182

public Task(String taskId, String projectId, String priority, String status, String title) {

183

this.taskId = taskId;

184

this.projectId = projectId;

185

this.priority = priority;

186

this.status = status;

187

this.title = title;

188

}

189

}

190

191

// Usage with hierarchical indices

192

KVStore store = new LevelDB(new File("./tasks"));

193

194

// Add tasks for different projects

195

store.write(new Task("t1", "proj1", "high", "open", "Implement feature A"));

196

store.write(new Task("t2", "proj1", "medium", "open", "Write tests"));

197

store.write(new Task("t3", "proj1", "high", "closed", "Fix bug #123"));

198

store.write(new Task("t4", "proj2", "low", "open", "Update documentation"));

199

200

// Query high priority tasks for project 1

201

KVStoreView<Task> highPriorityProj1 = store.view(Task.class)

202

.index("priority")

203

.parent("proj1") // Filter by parent project ID

204

.first("high")

205

.last("high");

206

207

// Query all tasks for project 1 by status

208

KVStoreView<Task> proj1ByStatus = store.view(Task.class)

209

.index("status")

210

.parent("proj1");

211

212

// Query open tasks for project 2

213

KVStoreView<Task> openProj2 = store.view(Task.class)

214

.index("status")

215

.parent("proj2")

216

.first("open")

217

.last("open");

218

```

219

220

### Copy vs Reference Indexing

221

222

Control whether index entries store full object data or just references.

223

224

**Usage Examples:**

225

226

```java

227

public class Product {

228

@KVIndex

229

public String productId;

230

231

@KVIndex(value = "category", copy = false) // Reference index (default)

232

public String category;

233

234

@KVIndex(value = "price", copy = true) // Copy index - stores full object data

235

public double price;

236

237

@KVIndex(value = "inStock", copy = true) // Copy index for fast access

238

public boolean inStock;

239

240

public String name;

241

public String description;

242

243

public Product(String id, String category, double price, boolean inStock, String name) {

244

this.productId = id;

245

this.category = category;

246

this.price = price;

247

this.inStock = inStock;

248

this.name = name;

249

}

250

}

251

252

// Copy indices provide faster iteration since no additional lookups are needed

253

// Reference indices save disk space but require additional lookups during iteration

254

255

// Fast iteration over products by price (copy index)

256

for (Product p : store.view(Product.class).index("price").first(10.0).last(50.0)) {

257

// No additional lookup needed - object data stored in index

258

System.out.println(p.name + ": $" + p.price);

259

}

260

261

// Slower iteration over products by category (reference index)

262

for (Product p : store.view(Product.class).index("category").first("electronics")) {

263

// Additional lookup needed to get full object data

264

System.out.println(p.name + " in " + p.category);

265

}

266

```

267

268

### Array Indexing

269

270

Index array fields for multi-value queries.

271

272

**Usage Examples:**

273

274

```java

275

public class Document {

276

@KVIndex

277

public String documentId;

278

279

@KVIndex("tags")

280

public String[] tags;

281

282

@KVIndex("scores")

283

public int[] scores;

284

285

public String title;

286

287

public Document(String id, String title, String[] tags, int[] scores) {

288

this.documentId = id;

289

this.title = title;

290

this.tags = tags;

291

this.scores = scores;

292

}

293

}

294

295

// Usage with array indices

296

Document doc1 = new Document("doc1", "Java Guide",

297

new String[]{"java", "programming", "tutorial"},

298

new int[]{95, 87, 92});

299

Document doc2 = new Document("doc2", "Python Basics",

300

new String[]{"python", "programming", "beginner"},

301

new int[]{88, 91, 85});

302

303

store.write(doc1);

304

store.write(doc2);

305

306

// Note: Array indexing creates entries for each array element

307

// Query documents with "programming" tag

308

for (Document d : store.view(Document.class).index("tags").first("programming").last("programming")) {

309

System.out.println("Found: " + d.title);

310

}

311

```

312

313

### Type Introspection and Metadata

314

315

Access index metadata and configuration for stored types.

316

317

```java { .api }

318

/**

319

* Wrapper around types managed in a KVStore, providing easy access to their indexed fields.

320

*/

321

public class KVTypeInfo {

322

public KVTypeInfo(Class<?> type);

323

public Class<?> type();

324

public Object getIndexValue(String indexName, Object instance) throws Exception;

325

public Stream<KVIndex> indices();

326

}

327

```

328

329

**Usage Examples:**

330

331

```java

332

// Introspect a class to see its indices

333

KVTypeInfo typeInfo = new KVTypeInfo(Person.class);

334

335

System.out.println("Type: " + typeInfo.type().getSimpleName());

336

System.out.println("Indices:");

337

338

typeInfo.indices().forEach(index -> {

339

System.out.println(" - " + index.value() +

340

(index.parent().isEmpty() ? "" : " (parent: " + index.parent() + ")") +

341

(index.copy() ? " [copy]" : " [reference]"));

342

});

343

344

// Get index value from an instance

345

Person person = new Person("p1", "Alice", 30, true);

346

String nameValue = (String) typeInfo.getIndexValue("name", person);

347

Integer ageValue = (Integer) typeInfo.getIndexValue("age", person);

348

```

349

350

### Accessor Interface

351

352

Internal interface for accessing field and method values used by the type introspection system.

353

354

```java { .api }

355

/**

356

* Abstracts the difference between invoking a Field and a Method.

357

*/

358

interface Accessor {

359

/**

360

* Get the value from the specified instance.

361

* @param instance - The object instance to access

362

* @return The field or method return value

363

* @throws ReflectiveOperationException If access fails

364

*/

365

Object get(Object instance) throws ReflectiveOperationException;

366

367

/**

368

* Get the type of the field or method return value.

369

* @return The field type or method return type

370

*/

371

Class<?> getType();

372

}

373

```