public RollupTreeNode build(EtlJobConfig.EtlTable tableMeta) {
        List<EtlJobConfig.EtlIndex> indexes = tableMeta.indexes;
        List<EtlJobConfig.EtlIndex> indexMetas = new ArrayList<>();
        EtlJobConfig.EtlIndex baseIndex = null;
        for (EtlJobConfig.EtlIndex indexMeta : indexes) {
            if (indexMeta.isBaseIndex) {
                baseIndex = indexMeta;
                continue;
            }
            indexMetas.add(indexMeta);
        }
        List<EtlJobConfig.EtlColumn> baseIndexColumns = baseIndex.columns;
        List<String> baseKeyColumns = new ArrayList<>();
        List<String> baseValueColumns = new ArrayList<>();
        for (EtlJobConfig.EtlColumn columnMeta : baseIndexColumns) {
            if (columnMeta.isKey) {
                baseKeyColumns.add(columnMeta.columnName);
            } else {
                baseValueColumns.add(columnMeta.columnName);
            }
        }
        RollupTreeNode root = new RollupTreeNode();
        root.parent = null;
        root.keyColumnNames = baseKeyColumns;
        root.valueColumnNames = baseValueColumns;
        root.indexId = baseIndex.indexId;
        root.indexMeta = baseIndex;

        // sort the index metas to make sure the column number decrease
        Collections.sort(indexMetas, new EtlJobConfig.EtlIndexComparator().reversed());
        for (int i = 0; i < indexMetas.size(); ++i) {
            List<String> keyColumns = new ArrayList<>();
            List<String> valueColumns = new ArrayList<>();
            for (EtlJobConfig.EtlColumn column : indexMetas.get(i).columns) {
                if (column.isKey) {
                    keyColumns.add(column.columnName);
                } else {
                    valueColumns.add(column.columnName);
                }
            }
            if (!insertIndex(root, indexMetas.get(i), keyColumns, valueColumns)) {
                throw new RuntimeException(String.format("can't find a parent rollup for rollup %s, rollup tree is %s",
                        indexMetas.get(i).toString(),
                        root.toString()));
            }
        }
        return root;
    }
@Test
    public void testBuild() {
        EtlJobConfig.EtlColumn column1 = new EtlJobConfig.EtlColumn(
                "column1", "INT",
                true, true,
                "NONE", "0",
                0, 0, 0);
        EtlJobConfig.EtlColumn column2 = new EtlJobConfig.EtlColumn(
                "column2", "SMALLINT",
                true, true,
                "NONE", "0",
                0, 0, 0);
        EtlJobConfig.EtlColumn column3 = new EtlJobConfig.EtlColumn(
                "column3", "VARCHAR",
                true, true,
                "NONE", "",
                0, 0, 0);
        EtlJobConfig.EtlColumn column4 = new EtlJobConfig.EtlColumn(
                "column4", "INT",
                true, false,
                "SUM", "",
                0, 0, 0);
        List<EtlJobConfig.EtlColumn> baseColumns = new ArrayList<>();
        baseColumns.add(column1);
        baseColumns.add(column2);
        baseColumns.add(column3);
        baseColumns.add(column4);
        EtlJobConfig.EtlIndex baseIndex = new EtlJobConfig.EtlIndex(10000,
                baseColumns, 12345, "DUPLICATE", true);
        List<EtlJobConfig.EtlColumn> roll1Columns = new ArrayList<>();
        roll1Columns.add(column1);
        roll1Columns.add(column2);
        roll1Columns.add(column4);
        EtlJobConfig.EtlIndex roll1Index = new EtlJobConfig.EtlIndex(10001,
                roll1Columns, 12346, "AGGREGATE", false);
        List<EtlJobConfig.EtlColumn> roll2Columns = new ArrayList<>();
        roll2Columns.add(column1);
        roll2Columns.add(column4);
        EtlJobConfig.EtlIndex roll2Index = new EtlJobConfig.EtlIndex(10002,
                roll2Columns, 12347, "AGGREGATE", false);

        List<EtlJobConfig.EtlColumn> roll3Columns = new ArrayList<>();
        roll3Columns.add(column3);
        roll3Columns.add(column4);
        EtlJobConfig.EtlIndex roll3Index = new EtlJobConfig.EtlIndex(10003,
                roll3Columns, 12348, "AGGREGATE", false);

        List<EtlJobConfig.EtlColumn> roll4Columns = new ArrayList<>();
        roll4Columns.add(column1);
        EtlJobConfig.EtlColumn newColumn2 = new EtlJobConfig.EtlColumn(
                "column2", "SMALLINT",
                true, false,
                "SUM", "0",
                0, 0, 0);
        roll4Columns.add(newColumn2);
        EtlJobConfig.EtlIndex roll4Index = new EtlJobConfig.EtlIndex(10004,
                roll4Columns, 12349, "AGGREGATE", false);

        List<EtlJobConfig.EtlIndex> indexes = new ArrayList<>();
        indexes.add(baseIndex);
        indexes.add(roll1Index);
        indexes.add(roll2Index);
        indexes.add(roll3Index);
        indexes.add(roll4Index);
        EtlJobConfig.EtlTable table = new EtlJobConfig.EtlTable(indexes, null);

        MinimumCoverageRollupTreeBuilder builder = new MinimumCoverageRollupTreeBuilder();
        RollupTreeNode resultNode = builder.build(table);
        Assert.assertEquals(resultNode.parent, null);
        Assert.assertEquals(resultNode.indexId, 10000);
        Assert.assertEquals(resultNode.level, 0);
        Assert.assertEquals(resultNode.children.size(), 2);

        RollupTreeNode index1Node = resultNode.children.get(0);
        Assert.assertEquals(index1Node.parent.indexId, 10000);
        Assert.assertEquals(index1Node.indexId, 10001);
        Assert.assertEquals(index1Node.level, 1);
        Assert.assertEquals(index1Node.children.size(), 2);

        RollupTreeNode index3Node = resultNode.children.get(1);
        Assert.assertEquals(index3Node.parent.indexId, 10000);
        Assert.assertEquals(index3Node.indexId, 10003);
        Assert.assertEquals(index3Node.level, 1);
        Assert.assertEquals(index3Node.children, null);

        RollupTreeNode index2Node = index1Node.children.get(0);
        Assert.assertEquals(index2Node.parent.indexId, 10001);
        Assert.assertEquals(index2Node.indexId, 10002);
        Assert.assertEquals(index2Node.level, 2);
        Assert.assertEquals(index2Node.children, null);

        RollupTreeNode index4Node = index1Node.children.get(1);
        Assert.assertEquals(index4Node.parent.indexId, 10001);
        Assert.assertEquals(index4Node.indexId, 10004);
        Assert.assertEquals(index4Node.level, 2);
        Assert.assertEquals(index4Node.children, null);
    }