org.apache.calcite.rel.core.Aggregate类的使用及代码示例

x33g5p2x  于2022-01-16 转载在 其他  
字(18.8k)|赞(0)|评价(0)|浏览(206)

本文整理了Java中org.apache.calcite.rel.core.Aggregate类的一些代码示例,展示了Aggregate类的具体用法。这些代码示例主要来源于Github/Stackoverflow/Maven等平台,是从一些精选项目中提取出来的代码,具有较强的参考意义,能在一定程度帮忙到你。Aggregate类的具体详情如下:
包路径:org.apache.calcite.rel.core.Aggregate
类名称:Aggregate

Aggregate介绍

[英]Relational operator that eliminates duplicates and computes totals.

It corresponds to the GROUP BY operator in a SQL query statement, together with the aggregate functions in the SELECTclause.

Rules:

  • org.apache.calcite.rel.rules.AggregateProjectPullUpConstantsRule
  • org.apache.calcite.rel.rules.AggregateExpandDistinctAggregatesRule
  • org.apache.calcite.rel.rules.AggregateReduceFunctionsRule.
    [中]消除重复项并计算总计的关系运算符。
    它与SQL查询语句中的GROUP BY运算符以及SELECT子句中的聚合函数相对应。
    规则:
    *组织。阿帕奇。方解石雷尔。规则。聚合项目PullupConstantsRule
    *组织。阿帕奇。方解石雷尔。规则。聚合ExpandDistingTagGregatesRule
    *组织。阿帕奇。方解石雷尔。规则。AggregateReduceFunctionsRule。

代码示例

代码示例来源:origin: apache/incubator-druid

final Aggregate aggregate = call.rel(0);
final Project project = call.rel(1);
final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
final List<AggregateCall> newCalls = new ArrayList<>(aggregate.getAggCallList().size());
final List<RexNode> newProjects = new ArrayList<>(project.getChildExps());
final List<RexNode> newCasts = new ArrayList<>(aggregate.getGroupCount() + aggregate.getAggCallList().size());
final RelDataTypeFactory typeFactory = aggregate.getCluster().getTypeFactory();
for (int fieldNumber : aggregate.getGroupSet()) {
 newCasts.add(rexBuilder.makeInputRef(project.getChildExps().get(fieldNumber).getType(), fieldNumber));
for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
 AggregateCall newCall = null;
  final RexNode rexNode = project.getChildExps().get(Iterables.getOnlyElement(aggregateCall.getArgList()));
 final RelDataType oldType = aggregate.getRowType().getFieldList().get(i).getType();
if (!newCalls.equals(aggregate.getAggCallList())) {
 final RelBuilder relBuilder = call
   .builder()
   .push(project.getInput())
   .project(newProjects);
   aggregate.getGroupSet(),
   aggregate.getGroupSets()
 );

代码示例来源:origin: apache/hive

@Override
public void onMatch(RelOptRuleCall call) {
 final RelBuilder relBuilder = call.builder();
 final Aggregate aggRel = (Aggregate) call.rel(0);
 final RexBuilder rexBuilder = aggRel.getCluster().getRexBuilder();
 final Map<AggregateCall, Integer> mapping = new HashMap<>();
 final List<Integer> indexes = new ArrayList<>();
 final List<AggregateCall> aggCalls = aggRel.getAggCallList();
 final List<AggregateCall> newAggCalls = new ArrayList<>(aggCalls.size());
 int nextIdx = aggRel.getGroupCount() + aggRel.getIndicatorCount();
 for (int i = 0; i < aggCalls.size(); i++) {
  AggregateCall aggCall = aggCalls.get(i);
  if (aggCall.getAggregation().getKind() == SqlKind.COUNT && !aggCall.isDistinct()) {
   final List<Integer> args = aggCall.getArgList();
   final List<Integer> nullableArgs = new ArrayList<>(args.size());
   for (int arg : args) {
    if (aggRel.getInput().getRowType().getFieldList().get(arg).getType().isNullable()) {
     nullableArgs.add(arg);
  final Aggregate newAggregate = aggRel.copy(aggRel.getTraitSet(), aggRel.getInput(),
      aggRel.indicator, aggRel.getGroupSet(), aggRel.getGroupSets(),
      newAggCalls);
  if (identity) {
   call.transformTo(newAggregate);
  } else {
   final int offset = aggRel.getGroupCount() + aggRel.getIndicatorCount();
   final List<RexNode> projList = Lists.newArrayList();
   for (int i = 0; i < offset; ++i) {
    projList.add(

代码示例来源:origin: apache/hive

@Override public void onMatch(RelOptRuleCall call) {
 final HiveSemiJoin semijoin= call.rel(0);
 final RelNode left = call.rel(1);
 final Aggregate rightAggregate= call.rel(2);
 if(rightAggregate.getGroupType() != Aggregate.Group.SIMPLE) {
  return;
 if(!rightAggregate.getAggCallList().isEmpty()) {
  return;
 boolean shouldTransform = joinInfo.rightSet().equals(
   ImmutableBitSet.range(rightAggregate.getGroupCount()));
 if(shouldTransform) {
  final RelBuilder relBuilder = call.builder();
  RelNode newRightInput = relBuilder.project(relBuilder.push(rightAggregate.getInput()).
    fields(rightAggregate.getGroupSet().asList())).build();
  RelNode newSemiJoin = call.builder().push(left).push(newRightInput)
    .semiJoin(semijoin.getCondition()).build();

代码示例来源:origin: apache/hive

private static boolean isEmptyGrpAggr(RelNode gbNode) {
 // Verify if both groupset and aggrfunction are empty)
 Aggregate aggrnode = (Aggregate) gbNode;
 if (aggrnode.getGroupSet().isEmpty() && aggrnode.getAggCallList().isEmpty()) {
  return true;
 }
 return false;
}

代码示例来源:origin: apache/incubator-druid

@Override
public boolean matches(final RelOptRuleCall call)
{
 final Aggregate aggregate = call.rel(0);
 final Project project = call.rel(1);
 if (aggregate.indicator || aggregate.getGroupSets().size() != 1) {
  return false;
 }
 for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
  if (isOneArgAggregateCall(aggregateCall)
    && isThreeArgCase(project.getChildExps().get(Iterables.getOnlyElement(aggregateCall.getArgList())))) {
   return true;
  }
 }
 return false;
}

代码示例来源:origin: apache/incubator-druid

final int fieldCount = aggregate.getGroupCount() + aggregate.getAggCallList().size();
if (fieldCount != aggregate.getRowType().getFieldCount()) {
 throw new ISE(
   "WTF, expected[%s] to have[%s] fields but it had[%s]",
   aggregate,
   fieldCount,
   aggregate.getRowType().getFieldCount()
 );
final ImmutableBitSet callsToKeep = projectBits.intersect(
  ImmutableBitSet.range(aggregate.getGroupCount(), fieldCount)
);
if (callsToKeep.cardinality() < aggregate.getAggCallList().size()) {
  newAggregateCalls.add(aggregate.getAggCallList().get(i - aggregate.getGroupCount()));
 final Aggregate newAggregate = aggregate.copy(
   aggregate.getTraitSet(),
   aggregate.getInput(),
   aggregate.indicator,
   aggregate.getGroupSet(),
   aggregate.getGroupSets(),
   newAggregateCalls
 );
 final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
 for (int i = 0; i < aggregate.getGroupCount(); i++) {

代码示例来源:origin: apache/hive

@Override
public void onMatch(RelOptRuleCall call) {
 final Aggregate aggregate = call.rel(0);
 final Join join = call.rel(1);
 final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
 final RelBuilder relBuilder = call.builder();
 for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
  if (aggregateCall.getAggregation().unwrap(SqlSplittableAggFunction.class)
    == null) {
   return;
 if (!allowFunctions && !aggregate.getAggCallList().isEmpty()) {
  return;
 final ImmutableBitSet aggregateColumns = aggregate.getGroupSet();
  final boolean unique;
  if (!allowFunctions) {
   assert aggregate.getAggCallList().isEmpty();
       : Mappings.createShiftMapping(fieldCount + offset, 0, offset,
         fieldCount);
   for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
    final SqlAggFunction aggregation = aggCall.e.getAggregation();
    final SqlSplittableAggFunction splitter =
      Preconditions.checkNotNull(
        aggregation.unwrap(SqlSplittableAggFunction.class));
    final AggregateCall call1;
    if (fieldSet.contains(ImmutableBitSet.of(aggCall.e.getArgList()))) {

代码示例来源:origin: apache/hive

public void onMatch(RelOptRuleCall call) {
 final LogicalCorrelate correlate = call.rel(0);
 final RelNode left = call.rel(1);
 final Project aggOutputProject = call.rel(2);
 if (!aggregate.getGroupSet().isEmpty()) {
  return;
 final List<AggregateCall> aggCalls = aggregate.getAggCallList();
 final Set<Integer> isCountStar = Sets.newHashSet();
  int nFields = left.getRowType().getFieldCount();
  ImmutableBitSet allCols = ImmutableBitSet.range(nFields);
 int nullIndicatorPos = join.getRowType().getFieldCount() - 1;
         cluster.getTypeFactory().createTypeWithNullability(
   argList = Lists.newArrayList();
   for (int aggArg : aggCall.getArgList()) {
    argList.add(aggArg + groupCount);
          aggregate.getGroupCount(), groupCount));
     ImmutableBitSet.range(groupCount);
 Aggregate newAggregate =
   (Aggregate) relBuilder.push(joinOutputProject)

代码示例来源:origin: apache/hive

if (!joinInfo.rightSet().equals(
  ImmutableBitSet.range(aggregate.getGroupCount()))) {
 call.transformTo(topOperator.copy(topOperator.getTraitSet(), ImmutableList.of(left)));
 return;
final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
for (int key : joinInfo.rightKeys) {
 newRightKeyBuilder.add(aggregateKeys.get(key));
final RelNode newRight = aggregate.getInput();
final RexNode newCondition =
  RelOptUtil.createEquiJoinCondition(left, joinInfo.leftKeys, newRight,
if(aggregate.getInput() instanceof HepRelVertex
  && ((HepRelVertex)aggregate.getInput()).getCurrentRel() instanceof  Join) {
 Join rightJoin = (Join)(((HepRelVertex)aggregate.getInput()).getCurrentRel());
 List<RexNode> projects = new ArrayList<>();
 for(int i=0; i<rightJoin.getRowType().getFieldCount(); i++){
  projects.add(rexBuilder.makeInputRef(rightJoin, i));
 RelNode topProject =  call.builder().push(rightJoin).project(projects, rightJoin.getRowType().getFieldNames(),
                                true).build();
 semi = call.builder().push(left).push(topProject).semiJoin(newCondition).build();
} else {
 semi = call.builder().push(left).push(aggregate.getInput()).semiJoin(newCondition).build();
call.transformTo(topOperator.copy(topOperator.getTraitSet(), ImmutableList.of(semi)));

代码示例来源:origin: apache/hive

final RelNode input = agg.getInput();
final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
final List<RexNode> aggPullUpPredicates = new ArrayList<>();
final RexBuilder rexBuilder = agg.getCluster().getRexBuilder();
ImmutableBitSet groupKeys = agg.getGroupSet();
Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
  input.getRowType().getFieldCount(), agg.getRowType().getFieldCount());
 if (!rCols.isEmpty() && groupKeys.contains(rCols)) {
  r = r.accept(new RexPermuteInputsShuttle(m, input));
  aggPullUpPredicates.add(r);

代码示例来源:origin: org.apache.calcite/calcite-core

final RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();
final List<RelDataTypeField> origFields =
  aggRel.getRowType().getFieldList();
final int[] adjustments = new int[origFields.size()];
int j = 0;
for (int i : aggRel.getGroupSet()) {
 adjustments[j] = i - j;
 j++;
 if (canPush(aggRel, rCols)) {
  pushedConditions.add(
    condition.accept(
      new RelOptUtil.RexInputConverter(rexBuilder, origFields,
        aggRel.getInput(0).getRowType().getFieldList(),
        adjustments)));
 } else {
final RelBuilder builder = call.builder();
RelNode rel =
  builder.push(aggRel.getInput()).filter(pushedConditions).build();
if (rel == aggRel.getInput(0)) {
 return;
rel = aggRel.copy(aggRel.getTraitSet(), ImmutableList.of(rel));
rel = builder.push(rel).filter(remainingConditions).build();
call.transformTo(rel);

代码示例来源:origin: apache/drill

boolean groupingSetsExpression = false;
if (groupBy.indicator) {
 Group aggregateType = Aggregate.Group.induce(groupBy.getGroupSet(),
     groupBy.getGroupSets());
 if (aggregateType == Group.ROLLUP) {
  b = ASTBuilder.construct(HiveParser.TOK_ROLLUP_GROUPBY, "TOK_ROLLUP_GROUPBY");
 RexInputRef iRef = new RexInputRef(groupBy.getGroupSet().nth(pos),
   groupBy.getCluster().getTypeFactory().createSqlType(SqlTypeName.ANY));
 b.add(iRef.accept(new RexVisitor(schema)));
for (int pos = 0; pos < groupBy.getGroupCount(); pos++) {
 if (!hiveAgg.getAggregateColumnsOrder().contains(pos)) {
  RexInputRef iRef = new RexInputRef(groupBy.getGroupSet().nth(pos),
    groupBy.getCluster().getTypeFactory().createSqlType(SqlTypeName.ANY));
  b.add(iRef.accept(new RexVisitor(schema)));
 for(ImmutableBitSet groupSet: groupBy.getGroupSets()) {
  ASTBuilder expression = ASTBuilder.construct(
      HiveParser.TOK_GROUPING_SETS_EXPRESSION, "TOK_GROUPING_SETS_EXPRESSION");
  for (int i : groupSet) {
   RexInputRef iRef = new RexInputRef(i, groupBy.getCluster().getTypeFactory()
     .createSqlType(SqlTypeName.ANY));
   expression.add(iRef.accept(new RexVisitor(schema)));
if (!groupBy.getGroupSet().isEmpty()) {
 hiveAST.groupBy = b.node();

代码示例来源:origin: apache/hive

Map<AggregateCall, RexNode> aggCallMapping,
 List<RexNode> inputExprs) {
final int nGroups = oldAggRel.getGroupCount();
final RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
final RelDataTypeFactory typeFactory = oldAggRel.getCluster().getTypeFactory();
final int iAvgInput = oldCall.getArgList().get(0);
final RelDataType sum0InputType = typeFactory.createTypeWithNullability(
  getFieldType(oldAggRel.getInput(), iAvgInput), true);
final RelDataType sumReturnType = getSumReturnType(
  rexBuilder.getTypeFactory(), sum0InputType, oldCall.getType());
final AggregateCall sumCall =
  AggregateCall.create(
    new HiveSqlSumAggFunction(
      oldCall.isDistinct(),
    oldCall.getArgList(),
    oldCall.filterArg,
    oldAggRel.getGroupCount(),
    oldAggRel.getInput(),
    null,
    null);
  rexBuilder.addAggCall(sumCall,
    nGroups,
    oldAggRel.indicator,

代码示例来源:origin: apache/hive

@Override
public void onMatch(RelOptRuleCall call) {
 final Aggregate agg = call.rel(0);
 final Union union = call.rel(1);
 final RexBuilder rexBuilder =
   agg.getCluster().getRexBuilder();
 List<RexNode> joinConjs = new ArrayList<>();
 List<RexNode> filterConjs = new ArrayList<>();
 int groupCount = agg.getGroupCount();
 int totalCount = agg.getGroupCount() + agg.getAggCallList().size();
 for (int leftPos = 0, rightPos = totalCount;
    leftPos < groupCount; leftPos++, rightPos++) {
  RexNode leftRef = rexBuilder.makeInputRef(
    joinLeftInput.getRowType().getFieldList().get(leftPos).getType(), leftPos);
  RexNode rightRef = rexBuilder.makeInputRef(
    joinRightInput.getRowType().getFieldList().get(leftPos).getType(), rightPos);
  projExprs.add(rightRef);
  joinConjs.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
    joinLeftInput.getRowType().getFieldList().get(leftPos).getType(), leftPos);
  SqlAggFunction aggCall = agg.getAggCallList().get(i).getAggregation();
  switch (aggCall.getKind()) {
  case SUM:
 RelNode newNode = call.builder()
   .push(union.getInput(1))
   .push(union.getInput(0))

代码示例来源:origin: apache/hive

RelOptRuleCall ruleCall,
 Aggregate oldAggRel) {
RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
List<AggregateCall> oldCalls = oldAggRel.getAggCallList();
final int groupCount = oldAggRel.getGroupCount();
final int indicatorCount = oldAggRel.getIndicatorCount();
   rexBuilder.makeInputRef(
     getFieldType(oldAggRel, i),
     i));
final RelBuilder relBuilder = ruleCall.builder();
relBuilder.push(oldAggRel.getInput());
final List<RexNode> inputExprs = new ArrayList<>(relBuilder.fields());
  inputExprs.size() - relBuilder.peek().getRowType().getFieldCount();
if (extraArgCount > 0) {
 relBuilder.project(inputExprs,
   CompositeList.of(
     relBuilder.peek().getRowType().getFieldNames(),
     Collections.<String>nCopies(extraArgCount, null)));
relBuilder.project(projList, oldAggRel.getRowType().getFieldNames())
  .convert(oldAggRel.getRowType(), false);
ruleCall.transformTo(relBuilder.build());

代码示例来源:origin: Qihoo360/Quicksql

public void onMatch(RelOptRuleCall call) {
  final Aggregate aggregate = call.rel(0);
  final RelNode input = call.rel(1);
  if (!aggregate.getAggCallList().isEmpty() || aggregate.indicator) {
   return;
  }
  final RelMetadataQuery mq = call.getMetadataQuery();
  if (!SqlFunctions.isTrue(mq.areColumnsUnique(input, aggregate.getGroupSet()))) {
   return;
  }
  // Distinct is "GROUP BY c1, c2" (where c1, c2 are a set of columns on
  // which the input is unique, i.e. contain a key) and has no aggregate
  // functions. It can be removed.
  final RelNode newInput = convert(input, aggregate.getTraitSet().simplify());

  // If aggregate was projecting a subset of columns, add a project for the
  // same effect.
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(newInput);
  if (newInput.getRowType().getFieldCount()
    > aggregate.getRowType().getFieldCount()) {
   relBuilder.project(relBuilder.fields(aggregate.getGroupSet().asList()));
  }
  call.transformTo(relBuilder.build());
 }
}

代码示例来源:origin: apache/hive

if ((aggregate.getIndicatorCount() > 0)
  || (aggregate.getGroupSet().isEmpty())
  || fieldsUsed.contains(aggregate.getGroupSet())) {
 return aggregate;
final RelNode input = aggregate.getInput();
final RelDataType rowType = input.getRowType();
RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
final List<RexNode> newProjects = new ArrayList<>();
final List<RexNode> inputExprs = input.getChildExps();
if (inputExprs == null || inputExprs.isEmpty()) {
 return aggregate;
for (int key : aggregate.getGroupSet()) {
 for (int i = 0; i < rowType.getFieldCount(); i++) {
  if (aggregate.getGroupSet().get(i)) {
   newProjects.add(rexBuilder.makeLiteral(true));
  } else {
   newProjects.add(rexBuilder.makeInputRef(input, i));
 Aggregate newAggregate = new HiveAggregate(aggregate.getCluster(), aggregate.getTraitSet(), relBuilder.build(),
                       aggregate.getGroupSet(), null, aggregate.getAggCallList());
 return newAggregate;

代码示例来源:origin: apache/hive

ASTNode cond = where.getCondition().accept(new RexVisitor(schema, false, root.getCluster().getRexBuilder()));
hiveAST.where = ASTBuilder.where(cond);
ASTBuilder b;
boolean groupingSetsExpression = false;
Group aggregateType = groupBy.getGroupType();
switch (aggregateType) {
 case SIMPLE:
 RexInputRef iRef = new RexInputRef(groupBy.getGroupSet().nth(pos),
   groupBy.getCluster().getTypeFactory().createSqlType(SqlTypeName.ANY));
 b.add(iRef.accept(new RexVisitor(schema, false, root.getCluster().getRexBuilder())));
for (int pos = 0; pos < groupBy.getGroupCount(); pos++) {
 if (!hiveAgg.getAggregateColumnsOrder().contains(pos)) {
  RexInputRef iRef = new RexInputRef(groupBy.getGroupSet().nth(pos),
    groupBy.getCluster().getTypeFactory().createSqlType(SqlTypeName.ANY));
  b.add(iRef.accept(new RexVisitor(schema, false, root.getCluster().getRexBuilder())));
 for(ImmutableBitSet groupSet: groupBy.getGroupSets()) {
  ASTBuilder expression = ASTBuilder.construct(
      HiveParser.TOK_GROUPING_SETS_EXPRESSION, "TOK_GROUPING_SETS_EXPRESSION");
  for (int i : groupSet) {
   RexInputRef iRef = new RexInputRef(i, groupBy.getCluster().getTypeFactory()
if (!groupBy.getGroupSet().isEmpty()) {
 hiveAST.groupBy = b.node();

代码示例来源:origin: apache/hive

List<List<Integer>> cleanArgList, Map<Integer, Integer> map,
 List<Integer> sourceOfForCountDistinct) throws CalciteSemanticException {
List<RexNode> originalInputRefs = Lists.transform(aggr.getRowType().getFieldList(),
  new Function<RelDataTypeField, RexNode>() {
   @Override
 RexNode condition = rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, originalInputRefs
   .get(originalInputRefs.size() - 1), rexBuilder.makeExactLiteral(new BigDecimal(
   getGroupingIdValue(list, sourceOfForCountDistinct, aggr.getGroupCount()))));
 if (list.size() == 1) {
  int pos = list.get(0);
  RexNode notNull = rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
    originalInputRefs.get(pos));
  condition = rexBuilder.makeCall(SqlStdOperatorTable.AND, condition, notNull);
 aggregateCalls.add(aggregateCall);
Aggregate aggregate = new HiveAggregate(cluster, cluster.traitSetOf(HiveRelNode.CONVENTION), gbInputRel,
  ImmutableBitSet.of(), null, aggregateCalls);
 return aggregate;
} else {
 List<RexNode> originalAggrRefs = Lists.transform(aggregate.getRowType().getFieldList(),
   new Function<RelDataTypeField, RexNode>() {
    @Override

代码示例来源:origin: apache/hive

final RelDataType rowType = aggregate.getRowType();
  aggregate.getGroupSet().rebuild();
for (AggregateCall aggCall : aggregate.getAggCallList()) {
 for (int i : aggCall.getArgList()) {
  inputFieldsUsed.set(i);
final RelNode input = aggregate.getInput();
final Set<RelDataTypeField> inputExtraFields = Collections.emptySet();
final TrimResult trimResult =
ImmutableBitSet originalGroupSet = aggregate.getGroupSet();
ImmutableBitSet updatedGroupSet = generateNewGroupset(aggregate, fieldsUsed);
ImmutableBitSet gbKeysDeleted = originalGroupSet.except(updatedGroupSet);
ImmutableBitSet updatedGroupFields = ImmutableBitSet.range(originalGroupSet.cardinality());
int originalGroupCount = aggregate.getGroupSet().cardinality();
int j = originalGroupCount;
int usedAggCallCount = 0;
for (int i = 0; i < aggregate.getAggCallList().size(); i++) {
if(!updatedGroupSet.equals(aggregate.getGroupSet())) {
 newGroupSets = ImmutableList.of(newGroupSet);
} else {
 newGroupSets = ImmutableList.copyOf(
   Iterables.transform(aggregate.getGroupSets(),
    input1 -> Mappings.apply(inputMapping, input1)));

相关文章