summaryrefslogtreecommitdiffstats
path: root/yql/essentials/core/common_opt/yql_co_flow3.cpp
blob: 6c2f7090d95935f889b78907451d5be4f5c9d031 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "yql_co.h"

#include <yql/essentials/core/yql_join.h>
#include <yql/essentials/core/yql_opt_utils.h>

#include <yql/essentials/utils/log/log.h>

namespace NYql {
namespace {

using namespace NNodes;

TExprNode::TPtr EquiJoinPushAny(const TExprNode::TPtr& node, TExprContext& ctx, TOptimizeContext& optCtx) {
    // Add any to EquiJoin tree
    if (!IsEmitPruneKeysEnabled(optCtx.Types)) {
        return node;
    }

    auto equiJoin = TCoEquiJoin(node);
    auto equiJoinTree = equiJoin.Arg(equiJoin.ArgCount() - 2).Cast<TCoEquiJoinTuple>();

    if (auto result = PushAnyInEquiJoin(ctx, equiJoinTree); result != equiJoinTree.Ptr()) {
        return ctx.ChangeChild(*node, equiJoin.ArgCount() - 2, std::move(result));
    }

    return node;
}

TExprNode::TPtr EquiJoinEmitPruneKeys(const TExprNode::TPtr& node, TExprContext& ctx, TOptimizeContext& optCtx) {
    // Add PruneKeys to EquiJoin inputs
    if (!IsEmitPruneKeysEnabled(optCtx.Types)) {
        return node;
    }
    auto equiJoin = TCoEquiJoin(node);
    if (HasSetting(equiJoin.Arg(equiJoin.ArgCount() - 1).Ref(), "prune_keys_added")) {
        return node;
    }

    THashMap<TStringBuf, THashSet<TStringBuf>> columnsForPruneKeysExtractor;
    GetPruneKeysColumnsForJoinLeaves(equiJoin.Arg(equiJoin.ArgCount() - 2).Cast<TCoEquiJoinTuple>(), columnsForPruneKeysExtractor);

    TExprNode::TListType children;
    bool hasChanges = false;
    for (size_t i = 0; i + 2 < equiJoin.ArgCount(); ++i) {
        auto child = equiJoin.Arg(i).Cast<TCoEquiJoinInput>();
        auto list = child.List();
        auto scope = child.Scope();

        if (!scope.Ref().IsAtom()) {
            children.push_back(equiJoin.Arg(i).Ptr());
            continue;
        }

        THashSet<TString> columns;
        auto itemNames = columnsForPruneKeysExtractor.find(scope.Ref().Content());
        if (itemNames == columnsForPruneKeysExtractor.end() || itemNames->second.empty()) {
            children.push_back(equiJoin.Arg(i).Ptr());
            continue;
        }
        for (const auto& elem : itemNames->second) {
            columns.insert(TString(elem));
        }

        if (IsAlreadyDistinct(list.Ref(), columns)) {
            children.push_back(equiJoin.Arg(i).Ptr());
            continue;
        }
        auto pruneKeysCallable = IsOrdered(list.Ref(), columns) ? "PruneAdjacentKeys" : "PruneKeys";
        YQL_CLOG(DEBUG, Core) << "Add " << pruneKeysCallable << " to EquiJoin input #" << i << ", label " << scope.Ref().Content();
        children.push_back(ctx.Builder(child.Pos())
            .List()
                .Callable(0, pruneKeysCallable)
                    .Add(0, list.Ptr())
                    .Add(1, MakePruneKeysExtractorLambda(child.Ref(), columns, ctx))
                .Seal()
                .Add(1, scope.Ptr())
            .Seal()
            .Build());
        hasChanges = true;
    }

    if (!hasChanges) {
        return node;
    }

    children.push_back(equiJoin.Arg(equiJoin.ArgCount() - 2).Ptr());
    children.push_back(AddSetting(
        equiJoin.Arg(equiJoin.ArgCount() - 1).Ref(),
        equiJoin.Arg(equiJoin.ArgCount() - 1).Pos(),
        "prune_keys_added",
        nullptr,
        ctx));
    return ctx.ChangeChildren(*node, std::move(children));
}

} // namespace

void RegisterCoFlowCallables3(TCallableOptimizerMap& map) {
    using namespace std::placeholders;
    map["EquiJoin"] = [](const TExprNode::TPtr& node, TExprContext& ctx, TOptimizeContext& optCtx) {
        if (auto ret = EquiJoinPushAny(node, ctx, optCtx); ret != node) {
            YQL_CLOG(DEBUG, Core) << "EquiJoinPushAny";
            return ret;
        }

        if (auto ret = EquiJoinEmitPruneKeys(node, ctx, optCtx); ret != node) {
            YQL_CLOG(DEBUG, Core) << "EquiJoinEmitPruneKeys";
            return ret;
        }

        return node;
    };

}

}