如何使用CQEngine索引自定义Java Record类?求替代方案
使用CQEngine为动态列结构的Record类建立索引
当然可以用CQEngine实现这个需求!核心在于为你需要索引的列名自定义Attribute,把Record里的动态列名和值映射成CQEngine能识别的属性。下面我一步步给你讲实现方法,附上完整代码示例。
核心思路:自定义Attribute映射动态列
CQEngine的索引和查询都是基于Attribute接口的,而你的Record类用两个列表存储列名和对应值,所以需要为每个要索引的列名创建一个自定义Attribute实现,让它能根据列名从Record中取出对应的值。
步骤1:完善Record类(添加性能优化)
先给你的Record类加一个根据列名取值的辅助方法,同时提前缓存列名到索引的映射,避免每次查找都遍历列表:
import java.util.HashMap; import java.util.List; import java.util.Map; public class Record { private final List<String> columnNames; private final List<Object> values; private final Map<String, Integer> columnIndexCache; // 缓存列名与索引的映射 public Record(List<String> columnNames, List<Object> values) { this.columnNames = columnNames; this.values = values; // 初始化缓存,提升后续取值效率 this.columnIndexCache = new HashMap<>(); for (int i = 0; i < columnNames.size(); i++) { columnIndexCache.put(columnNames.get(i), i); } } public List<String> getColumnNames() { return columnNames; } public List<Object> getValues() { return values; } // 根据列名快速获取对应值 public Object getValueByColumnName(String columnName) { Integer index = columnIndexCache.get(columnName); return index != null ? values.get(index) : null; } }
步骤2:创建自定义ColumnAttribute
这个类实现CQEngine的Attribute接口,负责从Record中提取指定列名的值:
import com.googlecode.cqengine.attribute.Attribute; import com.googlecode.cqengine.query.option.QueryOptions; public class ColumnAttribute<T> implements Attribute<Record, T> { private final String columnName; private final Class<T> valueType; public ColumnAttribute(String columnName, Class<T> valueType) { this.columnName = columnName; this.valueType = valueType; } @Override public String getAttributeName() { return columnName; // 用列名作为属性名,便于识别 } @Override public Class<T> getValueType() { return valueType; // 指定属性值的类型,确保类型安全 } @Override public T getValue(Record record, QueryOptions queryOptions) { // 从Record中取出对应列的值,并转换为指定类型 Object rawValue = record.getValueByColumnName(columnName); return valueType.cast(rawValue); } }
步骤3:建立索引并执行查询
现在可以用CQEngine创建索引集合,为需要的列添加索引,然后执行各种查询:
import com.googlecode.cqengine.IndexedCollection; import com.googlecode.cqengine.support.collection.SimpleIndexedCollection; import com.googlecode.cqengine.index.hash.HashIndex; import static com.googlecode.cqengine.query.QueryFactory.equal; import static com.googlecode.cqengine.query.QueryFactory.greaterThan; import java.util.List; public class CQEngineDemo { public static void main(String[] args) { // 1. 定义需要索引的列属性 ColumnAttribute<String> USER_NAME_ATTR = new ColumnAttribute<>("username", String.class); ColumnAttribute<Integer> USER_AGE_ATTR = new ColumnAttribute<>("age", Integer.class); // 2. 创建IndexedCollection,用来存储和索引Record IndexedCollection<Record> recordCollection = new SimpleIndexedCollection<>(); // 3. 为指定列添加索引(HashIndex适合等值查询,SortedIndex适合范围查询) recordCollection.addIndex(HashIndex.onAttribute(USER_NAME_ATTR)); recordCollection.addIndex(HashIndex.onAttribute(USER_AGE_ATTR)); // 4. 添加测试数据 recordCollection.add(new Record(List.of("username", "age", "email"), List.of("alice", 30, "alice@example.com"))); recordCollection.add(new Record(List.of("username", "age", "email"), List.of("bob", 25, "bob@example.com"))); recordCollection.add(new Record(List.of("username", "age", "email"), List.of("charlie", 35, "charlie@example.com"))); // 5. 执行查询示例 // 示例1:查询username为alice的记录 System.out.println("查询username=alice的结果:"); recordCollection.retrieve(equal(USER_NAME_ATTR, "alice")) .forEach(record -> System.out.println(record.getValueByColumnName("username") + " | " + record.getValueByColumnName("age"))); // 示例2:查询年龄大于30的记录 System.out.println("\n查询age>30的结果:"); recordCollection.retrieve(greaterThan(USER_AGE_ATTR, 30)) .forEach(record -> System.out.println(record.getValueByColumnName("username") + " | " + record.getValueByColumnName("age"))); } }
可选优化点
- 选择合适的索引类型:根据查询场景选索引,比如
HashIndex适合等值查询,SortedIndex适合范围查询,UniqueIndex适合唯一值列等。 - 动态创建Attribute:如果需要索引的列名是动态的,可以在运行时根据列名列表批量创建
ColumnAttribute实例。
替代方案
如果不需要CQEngine支持的复杂查询(比如多条件组合、模糊查询等),也可以自己维护轻量的索引结构:
import java.util.*; public class CustomIndexDemo { // 自定义索引:列名 -> 值 -> 对应的Record列表 private final Map<String, Map<Object, List<Record>>> columnIndex = new HashMap<>(); // 指定需要索引的列 private final Set<String> indexedColumns = Set.of("username", "age"); public void addRecord(Record record) { for (String columnName : indexedColumns) { Object value = record.getValueByColumnName(columnName); if (value == null) continue; // 初始化索引结构 columnIndex.computeIfAbsent(columnName, k -> new HashMap<>()) .computeIfAbsent(value, k -> new ArrayList<>()) .add(record); } } public List<Record> query(String columnName, Object value) { return columnIndex.getOrDefault(columnName, Collections.emptyMap()) .getOrDefault(value, Collections.emptyList()); } public static void main(String[] args) { CustomIndexDemo demo = new CustomIndexDemo(); demo.addRecord(new Record(List.of("username", "age"), List.of("alice", 30))); demo.addRecord(new Record(List.of("username", "age"), List.of("bob", 25))); System.out.println("自定义索引查询结果:"); demo.query("username", "alice").forEach(record -> System.out.println(record.getValueByColumnName("username"))); } }
这个方案更轻量,但只适合简单的等值查询,无法支持CQEngine那样的复杂查询组合。
内容的提问来源于stack exchange,提问作者suraj1291993
相关产品推荐
相关产品推荐

