public Collection<Long> prune(int columnId, HashDistributionKey hashKey, int complex) {
        if (columnId == distributionColumns.size()) {
            // compute Hash Key
            long hashValue = hashKey.getHashValue();
            return Lists.newArrayList(bucketsList.get((int) ((hashValue & 0xffffffff) % hashMod)));
        }
        Column keyColumn = distributionColumns.get(columnId);
        PartitionColumnFilter filter = distributionColumnFilters.get(keyColumn.getName());
        if (null == filter) {
            // no filter in this column, no partition Key
            // return all subPartition
            return bucketsList;
        }

        List<LiteralExpr> inPredicateLiterals = filter.getInPredicateLiterals();
        if (null == inPredicateLiterals ||
                inPredicateLiterals.size() * complex > Config.max_distribution_pruner_recursion_depth) {
            LiteralExpr lowerBound = filter.getLowerBound();
            LiteralExpr upperBound = filter.getUpperBound();
            // equal one value
            if (filter.lowerBoundInclusive && filter.upperBoundInclusive
                    && lowerBound != null && upperBound != null
                    && 0 == lowerBound.compareLiteral(upperBound)) {
                try {
                    boolean isConvertToDate = PartitionUtil.isConvertToDate(keyColumn.getType(), lowerBound.getType());
                    hashKey.pushColumn(filter.getLowerBound(isConvertToDate), keyColumn.getType());
                    Collection<Long> result = prune(columnId + 1, hashKey, complex);
                    hashKey.popColumn();
                    return result;
                } catch (Exception e) {
                    LOG.warn("Prune distribution key {} with predicate {} failed:", keyColumn, filter, e);
                    return bucketsList;
                }
            }
            // return all SubPartition
            return bucketsList;
        }

        InPredicate inPredicate = filter.getInPredicate();
        if (null != inPredicate && !(inPredicate.getChild(0) instanceof SlotRef)) {
            // return all SubPartition
            return bucketsList;
        }

        Set<Long> resultSet = Sets.newHashSet();
        int inElementNum = inPredicateLiterals.size();
        int newComplex = inElementNum * complex;
        for (LiteralExpr expr : inPredicateLiterals) {
            hashKey.pushColumn(expr, keyColumn.getType());
            Collection<Long> subList = prune(columnId + 1, hashKey, newComplex);
            resultSet.addAll(subList);
            hashKey.popColumn();
            if (resultSet.size() >= bucketsList.size()) {
                break;
            }
        }
        return resultSet;
    }
@Test
    public void test2() {
        List<Long> tabletIds = Lists.newArrayListWithExpectedSize(300);
        for (long i = 0; i < 300; i++) {
            tabletIds.add(i);
        }

        // distribution columns
        Column dealDate = new Column("dealDate", Type.DATE, false);
        Column mainBrandId = new Column("main_brand_id", Type.CHAR, false);
        Column itemThirdCateId = new Column("item_third_cate_id", Type.CHAR, false);
        Column channel = new Column("channel", Type.CHAR, false);
        Column shopType = new Column("shop_type", Type.CHAR, false);
        List<Column> columns = Lists.newArrayList(dealDate, mainBrandId, itemThirdCateId, channel, shopType);

        // filters
        PartitionColumnFilter mainBrandFilter = new PartitionColumnFilter();
        List<Expr> inList = Lists.newArrayList();
        inList.add(new StringLiteral("1323"));
        inList.add(new StringLiteral("2528"));
        inList.add(new StringLiteral("9610"));
        inList.add(new StringLiteral("3893"));
        inList.add(new StringLiteral("6121"));
        mainBrandFilter.setInPredicate(
                new InPredicate(new FunctionCallExpr("abs", Lists.newArrayList(new SlotRef(null, "main_brand_id"))),
                        inList, false));

        Map<String, PartitionColumnFilter> filters = Maps.newHashMap();
        filters.put("main_brand_id", mainBrandFilter);

        HashDistributionPruner pruner = new HashDistributionPruner(tabletIds, columns, filters, tabletIds.size());

        Collection<Long> results = pruner.prune();
        Assert.assertEquals(tabletIds.size(), results.size());
    }