RareTopNOperator.java

1
/*
2
 * Copyright OpenSearch Contributors
3
 * SPDX-License-Identifier: Apache-2.0
4
 */
5
6
7
package org.opensearch.sql.planner.physical;
8
9
import com.google.common.annotations.VisibleForTesting;
10
import com.google.common.collect.ImmutableList;
11
import com.google.common.collect.Streams;
12
import java.util.AbstractMap;
13
import java.util.Collections;
14
import java.util.Comparator;
15
import java.util.HashMap;
16
import java.util.Iterator;
17
import java.util.LinkedHashMap;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.stream.Collectors;
21
import lombok.EqualsAndHashCode;
22
import lombok.Getter;
23
import lombok.RequiredArgsConstructor;
24
import lombok.ToString;
25
import org.opensearch.sql.ast.tree.RareTopN.CommandType;
26
import org.opensearch.sql.data.model.ExprTupleValue;
27
import org.opensearch.sql.data.model.ExprValue;
28
import org.opensearch.sql.expression.Expression;
29
import org.opensearch.sql.storage.bindingtuple.BindingTuple;
30
31
/**
32
 * Group the all the input {@link BindingTuple} by {@link RareTopNOperator#groupByExprList},
33
 * Calculate the rare result by using the {@link RareTopNOperator#fieldExprList}.
34
 */
35
@ToString
36
@EqualsAndHashCode(callSuper = false)
37
public class RareTopNOperator extends PhysicalPlan {
38
39
  @Getter
40
  private final PhysicalPlan input;
41
  @Getter
42
  private final CommandType commandType;
43
  @Getter
44
  private final Integer noOfResults;
45
  @Getter
46
  private final List<Expression> fieldExprList;
47
  @Getter
48
  private final List<Expression> groupByExprList;
49
50
  @EqualsAndHashCode.Exclude
51
  private final Group group;
52
  @EqualsAndHashCode.Exclude
53
  private Iterator<ExprValue> iterator;
54
55
  private static final Integer DEFAULT_NO_OF_RESULTS = 10;
56
57
58
  public RareTopNOperator(PhysicalPlan input, CommandType commandType,
59
      List<Expression> fieldExprList, List<Expression> groupByExprList) {
60
    this(input, commandType, DEFAULT_NO_OF_RESULTS, fieldExprList, groupByExprList);
61
  }
62
63
  /**
64
   * RareTopNOperator Constructor.
65
   *
66
   * @param input           Input {@link PhysicalPlan}
67
   * @param commandType     Enum for Rare/TopN command.
68
   * @param noOfResults     Number of results
69
   * @param fieldExprList   List of {@link Expression}
70
   * @param groupByExprList List of group by {@link Expression}
71
   */
72
  public RareTopNOperator(PhysicalPlan input, CommandType commandType, int noOfResults,
73
      List<Expression> fieldExprList,
74
      List<Expression> groupByExprList) {
75
    this.input = input;
76
    this.commandType = commandType;
77
    this.noOfResults = noOfResults;
78
    this.fieldExprList = fieldExprList;
79
    this.groupByExprList = groupByExprList;
80
    this.group = new Group();
81
  }
82
83
  @Override
84
  public <R, C> R accept(PhysicalPlanNodeVisitor<R, C> visitor, C context) {
85 1 1. accept : replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator::accept → KILLED
    return visitor.visitRareTopN(this, context);
86
  }
87
88
  @Override
89
  public List<PhysicalPlan> getChild() {
90 1 1. getChild : replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/RareTopNOperator::getChild → KILLED
    return Collections.singletonList(input);
91
  }
92
93
  @Override
94
  public boolean hasNext() {
95 2 1. hasNext : replaced boolean return with false for org/opensearch/sql/planner/physical/RareTopNOperator::hasNext → KILLED
2. hasNext : replaced boolean return with true for org/opensearch/sql/planner/physical/RareTopNOperator::hasNext → KILLED
    return iterator.hasNext();
96
  }
97
98
  @Override
99
  public ExprValue next() {
100 1 1. next : replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator::next → KILLED
    return iterator.next();
101
  }
102
103
  @Override
104
  public void open() {
105 1 1. open : removed call to org/opensearch/sql/planner/physical/PhysicalPlan::open → SURVIVED
    super.open();
106 1 1. open : negated conditional → KILLED
    while (input.hasNext()) {
107 1 1. open : removed call to org/opensearch/sql/planner/physical/RareTopNOperator$Group::push → KILLED
      group.push(input.next());
108
    }
109
    iterator = group.result().iterator();
110
  }
111
112
  @VisibleForTesting
113
  @RequiredArgsConstructor
114
  public class Group {
115
116
    private final Map<Key, Map<Key, Integer>> groupListMap = new HashMap<>();
117
118
    /**
119
     * Push the BindingTuple to Group.
120
     */
121
    public void push(ExprValue inputValue) {
122
      Key groupKey = new Key(inputValue, groupByExprList);
123
      Key fieldKey = new Key(inputValue, fieldExprList);
124
      groupListMap.computeIfAbsent(groupKey, k -> {
125
        Map<Key, Integer> map = new HashMap<>();
126
        map.put(fieldKey, 1);
127 1 1. lambda$push$0 : replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$0 → KILLED
        return map;
128
      });
129
      groupListMap.computeIfPresent(groupKey, (key, map) -> {
130 1 1. lambda$push$1 : replaced Integer return value with 0 for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$1 → SURVIVED
        map.computeIfAbsent(fieldKey, f -> 1);
131
        map.computeIfPresent(fieldKey, (field, count) -> {
132 2 1. lambda$push$2 : replaced Integer return value with 0 for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$2 → SURVIVED
2. lambda$push$2 : Replaced integer addition with subtraction → KILLED
          return count + 1;
133
        });
134 1 1. lambda$push$3 : replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$3 → KILLED
        return map;
135
      });
136
    }
137
138
    /**
139
     * Get the list of {@link BindingTuple} for each group.
140
     */
141
    public List<ExprValue> result() {
142
      ImmutableList.Builder<ExprValue> resultBuilder = new ImmutableList.Builder<>();
143
144 1 1. result : removed call to java/util/Map::forEach → KILLED
      groupListMap.forEach((groups, fieldMap) -> {
145
        Map<String, ExprValue> map = new LinkedHashMap<>();
146
        List<Key> result = find(fieldMap);
147 1 1. lambda$result$5 : removed call to java/util/List::forEach → KILLED
        result.forEach(field -> {
148 1 1. lambda$result$4 : removed call to java/util/Map::putAll → KILLED
          map.putAll(groups.keyMap(groupByExprList));
149 1 1. lambda$result$4 : removed call to java/util/Map::putAll → KILLED
          map.putAll(field.keyMap(fieldExprList));
150
          resultBuilder.add(ExprTupleValue.fromExprValueMap(map));
151
        });
152
      });
153
154 1 1. result : replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/RareTopNOperator$Group::result → KILLED
      return resultBuilder.build();
155
    }
156
157
    /**
158
     * Get a list of result.
159
     */
160
    public List<Key> find(Map<Key, Integer> map) {
161
      Comparator<Map.Entry<Key, Integer>> valueComparator;
162 1 1. find : negated conditional → KILLED
      if (CommandType.TOP.equals(commandType)) {
163
        valueComparator = Map.Entry.comparingByValue(Comparator.reverseOrder());
164
      } else {
165
        valueComparator = Map.Entry.comparingByValue();
166
      }
167
168 1 1. find : replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/RareTopNOperator$Group::find → KILLED
      return map.entrySet().stream().sorted(valueComparator).limit(noOfResults)
169
          .map(Map.Entry::getKey).collect(Collectors.toList());
170
    }
171
  }
172
173
  /**
174
   * Key.
175
   */
176
  @EqualsAndHashCode
177
  @VisibleForTesting
178
  public class Key {
179
180
    private final List<ExprValue> valueList;
181
182
    /**
183
     * Key constructor.
184
     */
185
    public Key(ExprValue value, List<Expression> exprList) {
186
      this.valueList = exprList.stream()
187 1 1. lambda$new$0 : replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$new$0 → KILLED
          .map(expr -> expr.valueOf(value.bindingTuples())).collect(Collectors.toList());
188
    }
189
190
    /**
191
     * Return the Map of key and key value.
192
     */
193
    public Map<String, ExprValue> keyMap(List<Expression> exprList) {
194
195 1 1. keyMap : replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/RareTopNOperator$Key::keyMap → KILLED
      return Streams.zip(
196
          exprList.stream().map(
197 1 1. lambda$keyMap$1 : replaced return value with "" for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$keyMap$1 → KILLED
              expression -> expression.toString()),
198
          valueList.stream(),
199
          AbstractMap.SimpleEntry::new
200 2 1. lambda$keyMap$2 : replaced return value with "" for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$keyMap$2 → KILLED
2. lambda$keyMap$3 : replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$keyMap$3 → KILLED
      ).collect(Collectors.toMap(key -> key.getKey(), key -> key.getValue()));
201
    }
202
  }
203
204
}

Mutations

85

1.1
Location : accept
Killed by : org.opensearch.sql.executor.ExplainTest.[engine:junit-jupiter]/[class:org.opensearch.sql.executor.ExplainTest]/[method:can_explain_rare_top_n()]
replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator::accept → KILLED

90

1.1
Location : getChild
Killed by : org.opensearch.sql.executor.ExplainTest.[engine:junit-jupiter]/[class:org.opensearch.sql.executor.ExplainTest]/[method:can_explain_rare_top_n()]
replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/RareTopNOperator::getChild → KILLED

95

1.1
Location : hasNext
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced boolean return with false for org/opensearch/sql/planner/physical/RareTopNOperator::hasNext → KILLED

2.2
Location : hasNext
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced boolean return with true for org/opensearch/sql/planner/physical/RareTopNOperator::hasNext → KILLED

100

1.1
Location : next
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator::next → KILLED

105

1.1
Location : open
Killed by : none
removed call to org/opensearch/sql/planner/physical/PhysicalPlan::open → SURVIVED

106

1.1
Location : open
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
negated conditional → KILLED

107

1.1
Location : open
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
removed call to org/opensearch/sql/planner/physical/RareTopNOperator$Group::push → KILLED

127

1.1
Location : lambda$push$0
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$0 → KILLED

130

1.1
Location : lambda$push$1
Killed by : none
replaced Integer return value with 0 for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$1 → SURVIVED

132

1.1
Location : lambda$push$2
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:top_n_without_group()]
Replaced integer addition with subtraction → KILLED

2.2
Location : lambda$push$2
Killed by : none
replaced Integer return value with 0 for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$2 → SURVIVED

134

1.1
Location : lambda$push$3
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/RareTopNOperator$Group::lambda$push$3 → KILLED

144

1.1
Location : result
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
removed call to java/util/Map::forEach → KILLED

147

1.1
Location : lambda$result$5
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
removed call to java/util/List::forEach → KILLED

148

1.1
Location : lambda$result$4
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_with_group()]
removed call to java/util/Map::putAll → KILLED

149

1.1
Location : lambda$result$4
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
removed call to java/util/Map::putAll → KILLED

154

1.1
Location : result
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/RareTopNOperator$Group::result → KILLED

162

1.1
Location : find
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:top_n_without_group()]
negated conditional → KILLED

168

1.1
Location : find
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/RareTopNOperator$Group::find → KILLED

187

1.1
Location : lambda$new$0
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$new$0 → KILLED

195

1.1
Location : keyMap
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/RareTopNOperator$Key::keyMap → KILLED

197

1.1
Location : lambda$keyMap$1
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with "" for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$keyMap$1 → KILLED

200

1.1
Location : lambda$keyMap$2
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with "" for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$keyMap$2 → KILLED

2.2
Location : lambda$keyMap$3
Killed by : org.opensearch.sql.planner.physical.RareTopNOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.RareTopNOperatorTest]/[method:rare_without_group()]
replaced return value with null for org/opensearch/sql/planner/physical/RareTopNOperator$Key::lambda$keyMap$3 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.9.0