Java 提高矩阵/表聚合和搜索的性能

Java 提高矩阵/表聚合和搜索的性能,java,mysql,algorithm,rdbms,sparse-matrix,Java,Mysql,Algorithm,Rdbms,Sparse Matrix,有一个产品特征矩阵。它有数千行(产品)和数百个功能。它具有二进制值,用于显示产品是否具有此功能。因此,它可能是一个包含40000行和900列的表 产品功能矩阵 pr f1 f2 f3 fn… 01 0 1 1 02 0 0 0310110 041010 ..... 首先,我必须找到具有一组给定特性Q的产品,例如Q=(f1=1,f5=1,f27=1)。简单的说,找到蓝色的车,掀背式的,三门的 结果1 给定Q=(f1=1,f5=1,f27=1) 相关产品:03、04、08。。。 第二,也是最

有一个产品特征矩阵。它有数千行(产品)和数百个功能。它具有二进制值,用于显示产品是否具有此功能。因此,它可能是一个包含40000行和900列的表


产品功能矩阵
pr f1 f2 f3 fn…
01 0 1 1
02 0 0
0310110
041010
.....

首先,我必须找到具有一组给定特性Q的产品,例如Q=(f1=1,f5=1,f27=1)。简单的说,找到蓝色的车,掀背式的,三门的


结果1
给定Q=(f1=1,f5=1,f27=1)
相关产品:03、04、08。。。

第二,也是最重要的,我必须找出有多少产品有一组特性Q,也有一个特性f_I(其中I-1..n)。换句话说,我们选择满足Q的行,并计算每列中有多少个1(进行总和聚合)。例如,有多少辆蓝色轿车、掀背车、三门车也有:柴油机、汽油机、氙气灯


结果2
给定Q=(f1=1,f5=1,f27=1)
总和f2=943
总和f3=543
总和f4=7
总和f6=432
....

当然,使用RDBMS解决这个任务是可能的,但它并不是那么有效——在一般情况下,它需要在每个列中进行完整扫描以查找产品和聚合。至少我不知道如何为这个任务构建有效的b树索引。Oracle位图索引可能会有所帮助,但我不能使用Oracle

目前,我们正在使用MySQL来完成这项任务,但效果不佳。实际上,我们使用整数表示(我们将特征分组并将整数存储在列中,而不是布尔值)来减少列的数量

可以将此矩阵视为稀疏二进制矩阵。把它完全存储在内存中并不是什么大问题。我想知道是否可以应用一些算法来处理稀疏矩阵、向量空间(SVD、矩阵向量乘法等等)。但它可能有助于找到满足向量Q的乘积,而不是聚合。问题更多地在于聚合的时间,而不是空间

也许,可以将矩阵存储为一个多链接列表,这将有助于查找产品并对每个列进行聚合


最后,问题是如何对待这项任务。查找具有给定功能的产品,然后计算具有附加功能的产品(按每列聚合)的最有效算法是什么。

如果我了解您当前的解决方案,您有一个表,其中每个产品有一行,每个功能有一列。这是一种解决问题的低效方法

三张桌子怎么样

“产品”(产品编号、产品名称)索引产品编号(产品清单)

“特征”(特征参考,描述)索引特征参考(可能特征的列表)

“productfeatures”(product_ref,feature_ref)索引product_ref,feature_ref和feature_ref,product_ref(每行代表一个产品的特征)

然后可以在表之间执行联接


从产品t1中选择*加入产品功能t2加入产品功能t3,其中t1.product\u ref=t2.product\u ref和t1.product\u ref=t3.product\u ref和t2.feature\u ref=45和t3.feature\u ref=67等请看一看我刚才做的这个示例,它遵循Jayde正确概述的内容,但更详细地说,相对于运行时间为0.02秒的1.25亿海报类别(汽车功能),最坏的情况是40K++*900列=3600万行,也就是说,这是一个婴儿


您可以按列排列数据。i、 e.为列中列出具有该特性的车辆/行设置一个位集

这允许您利用位集提供的快速和/或操作

使用这些功能,您应该能够实现少于2微秒的搜索和每个功能的计数

对于40000*900数据集,打印以下内容

average search time 1396 ns.
average count time 1234 ns.
这应该比使用RDBMS数据库快几个数量级。即使是一百万行,每行也不到50微秒

public static void main(String... args) throws IOException {
    final int rows = 40 * 1000;
    final int cols = 900;

    List<BitSet> features = new ArrayList<BitSet>();
    features.add(new BitSet(rows));
    features.add(new BitSet(rows));
    for (int i = 2; i < cols; i++) {
        final BitSet bs = new BitSet(rows);
        for (int j = 0; j < rows; j++)
            bs.set(j, j % i == 0);
        features.add(bs);
    }

    // perform the search
    int[] factors = new int[]{2, 5, 7};
    BitSet matches = new BitSet();
    long runs =  1000*1000;
    {
        long start = System.nanoTime();
        for (int i = 0; i < runs; i++) {
            // perform lookup.
            lookup(matches, features, factors);
        }
        long avgTime = (System.nanoTime() - start) / runs;
        System.out.println("average search time " + avgTime  + " ns.");
    }
    {
        long start = System.nanoTime();
        int count9 = 0;
        BitSet col9matched = new BitSet(cols);
        for (int i = 0; i < runs; i++) {
            final int index = 9;
            final BitSet feature = features.get(index);
            count9 = countMatches(col9matched, matches, feature);
        }
        long avgTime = (System.nanoTime() - start) / runs;
        System.out.println("average count time " + avgTime + " ns.");
    }
}

private static int countMatches(BitSet scratch, BitSet matches, BitSet feature) {
    // recycle.
    scratch.clear();
    scratch.or(matches);
    scratch.and(feature);
    return scratch.cardinality();
}

private static void lookup(BitSet matches, List<BitSet> data, int[] factors) {
    matches.clear();
    matches.or(data.get(factors[0]));
    for (int i = 1, factorsLength = factors.length; i < factorsLength; i++) {
        matches.and(data.get(factors[i]));
    }
}
publicstaticvoidmain(String…args)抛出IOException{
最终整数行=40*1000;
最终整数cols=900;
列表功能=新建ArrayList();
添加(新的位集(行));
添加(新的位集(行));
for(int i=2;ipublic static void main(String... args) throws IOException {
    final int rows = 40 * 1000;
    final int cols = 900;

    List<BitSet> features = new ArrayList<BitSet>();
    features.add(new BitSet(rows));
    features.add(new BitSet(rows));
    for (int i = 2; i < cols; i++) {
        final BitSet bs = new BitSet(rows);
        for (int j = 0; j < rows; j++)
            bs.set(j, j % i == 0);
        features.add(bs);
    }

    // perform the search
    int[] factors = new int[]{2, 5, 7};
    BitSet matches = new BitSet();
    long runs =  1000*1000;
    {
        long start = System.nanoTime();
        for (int i = 0; i < runs; i++) {
            // perform lookup.
            lookup(matches, features, factors);
        }
        long avgTime = (System.nanoTime() - start) / runs;
        System.out.println("average search time " + avgTime  + " ns.");
    }
    {
        long start = System.nanoTime();
        int count9 = 0;
        BitSet col9matched = new BitSet(cols);
        for (int i = 0; i < runs; i++) {
            final int index = 9;
            final BitSet feature = features.get(index);
            count9 = countMatches(col9matched, matches, feature);
        }
        long avgTime = (System.nanoTime() - start) / runs;
        System.out.println("average count time " + avgTime + " ns.");
    }
}

private static int countMatches(BitSet scratch, BitSet matches, BitSet feature) {
    // recycle.
    scratch.clear();
    scratch.or(matches);
    scratch.and(feature);
    return scratch.cardinality();
}

private static void lookup(BitSet matches, List<BitSet> data, int[] factors) {
    matches.clear();
    matches.or(data.get(factors[0]));
    for (int i = 1, factorsLength = factors.length; i < factorsLength; i++) {
        matches.and(data.get(factors[i]));
    }
}