You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:07:10