Skip to content

Commit

Permalink
[NO ISSUE][FUN] Implement array_reverse() function
Browse files Browse the repository at this point in the history
- user model changes: no
- storage format changes: no
- interface changes: no

details:
This is part of implementing array functions.
The array_reverse() takes an input list and returns
a new list with the elements in reverse.
array_reverse(list).

Change-Id: Ib9d9f8e760390a708d67a2cab357bf4722271381
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2725
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
  • Loading branch information
AliSolaiman authored and mhubail committed Jun 26, 2018
1 parent f6b2ade commit 6b31f73
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 0 deletions.
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

drop dataverse TinySocial if exists;
create dataverse TinySocial;

use TinySocial;


create type TinySocial.TwitterUserType as
{
`screen-name` : string,
lang : string,
friends_count : bigint,
statuses_count : bigint,
name : string,
followers_count : bigint
};

create type TinySocial.TweetMessageType as
closed {
tweetid : string,
user : TwitterUserType,
`sender-location` : point?,
`send-time` : datetime,
`referred-topics` : {{string}},
`message-text` : string
};

create dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`);
@@ -0,0 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

use TinySocial;

load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`));
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

use TinySocial;

{
"t1": (select array_reverse(t.`referred-topics`) from TweetMessages t order by t.tweetid),
"t2": (select array_reverse([5, 7, 19])),
"t3": (select array_reverse([5, 7.5, 19])),
"t4": (select array_reverse([5, 7.5, 19, "John"])),
"t5": (select array_reverse([3])),
"t6": (select array_reverse("non_array")),
"t7": (select array_reverse([])),
"t8": (select array_reverse(missing)),
"t9": (select array_reverse(null))
};
@@ -0,0 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

drop dataverse TinySocial;
@@ -0,0 +1 @@
{ "t1": [ { "$1": {{ "customization", "t-mobile" }} }, { "$1": {{ "voice-clarity", "verizon" }} }, { "$1": {{ "platform", "iphone" }} }, { "$1": {{ "voice-command", "samsung" }} }, { "$1": {{ "shortcut-menu", "verizon" }} }, { "$1": {{ "speed", "motorola" }} }, { "$1": {{ "voice-command", "sprint" }} }, { "$1": {{ "speed", "motorola" }} }, { "$1": {{ "voice-clarity", "iphone" }} }, { "$1": {{ "platform", "samsung" }} }, { "$1": {{ "shortcut-menu", "t-mobile" }} }, { "$1": {{ "voicemail-service", "verizon" }} } ], "t2": [ { "$2": [ 19, 7, 5 ] } ], "t3": [ { "$3": [ 19, 7.5, 5 ] } ], "t4": [ { "$4": [ "John", 19, 7.5, 5 ] } ], "t5": [ { "$5": [ 3 ] } ], "t6": [ { "$6": null } ], "t7": [ { "$7": [ ] } ], "t8": [ { } ], "t9": [ { "$9": null } ] }
Expand Up @@ -995,6 +995,11 @@
<expected-error>HYR0115: Cannot compare non-primitive values (in line 22, at column 8)</expected-error>
</compilation-unit>
</test-case>
<test-case FilePath="array_fun">
<compilation-unit name="array_reverse">
<output-dir compare="Text">array_reverse</output-dir>
</compilation-unit>
</test-case>
</test-group>
<test-group name="boolean">
<test-case FilePath="boolean">
Expand Down
Expand Up @@ -43,6 +43,7 @@
import org.apache.asterix.om.typecomputer.impl.AInt8TypeComputer;
import org.apache.asterix.om.typecomputer.impl.AIntervalTypeComputer;
import org.apache.asterix.om.typecomputer.impl.ALineTypeComputer;
import org.apache.asterix.om.typecomputer.impl.AListTypeComputer;
import org.apache.asterix.om.typecomputer.impl.APoint3DTypeComputer;
import org.apache.asterix.om.typecomputer.impl.APointTypeComputer;
import org.apache.asterix.om.typecomputer.impl.APolygonTypeComputer;
Expand Down Expand Up @@ -187,6 +188,8 @@ public enum SpatialFilterKind {
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-append", FunctionIdentifier.VARARGS);
public static final FunctionIdentifier ARRAY_POSITION =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-position", 2);
public static final FunctionIdentifier ARRAY_REVERSE =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-reverse", 1);

// objects
public static final FunctionIdentifier RECORD_MERGE =
Expand Down Expand Up @@ -1464,6 +1467,7 @@ public static FunctionInfo lookupFunction(FunctionIdentifier fid) {
// array functions
addFunction(ARRAY_APPEND, ArrayAppendTypeComputer.INSTANCE, true);
addFunction(ARRAY_POSITION, AInt32TypeComputer.INSTANCE, true);
addFunction(ARRAY_REVERSE, AListTypeComputer.INSTANCE, true);

// objects
addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true);
Expand Down
@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.asterix.om.typecomputer.impl;

import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.IAType;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;

/**
* A type computer that returns the same list type as the presumably input list at argument 0. If the argument is not a
* list, it returns "ANY".
*/
public class AListTypeComputer extends AbstractResultTypeComputer {
public static final AListTypeComputer INSTANCE = new AListTypeComputer();

private AListTypeComputer() {
}

@Override
protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
IAType argType = strippedInputTypes[0];
switch (argType.getTypeTag()) {
case ARRAY:
case MULTISET:
return argType;
default:
return BuiltinType.ANY;
}
}
}
@@ -0,0 +1,140 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.asterix.runtime.evaluators.functions;

import java.io.IOException;

import org.apache.asterix.builders.IAsterixListBuilder;
import org.apache.asterix.builders.OrderedListBuilder;
import org.apache.asterix.builders.UnorderedListBuilder;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.om.functions.IFunctionTypeInferer;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.AbstractCollectionType;
import org.apache.asterix.om.types.IAType;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
import org.apache.asterix.runtime.evaluators.common.ListAccessor;
import org.apache.asterix.runtime.functions.FunctionTypeInferers;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
import org.apache.hyracks.api.context.IHyracksTaskContext;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.data.std.api.IPointable;
import org.apache.hyracks.data.std.primitive.VoidPointable;
import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;

/**
* array_reverse(list) returns a new list with the entries of the original input list in reverse order. If the input is
* not a list, it returns "null".
*/
public class ArrayReverseDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
private IAType inputListType;

public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
@Override
public IFunctionDescriptor createFunctionDescriptor() {
return new ArrayReverseDescriptor();
}

@Override
public IFunctionTypeInferer createFunctionTypeInferer() {
// the type of the input list is needed in order to use the same type for the new returned list
return FunctionTypeInferers.SET_ARGUMENT_TYPE;
}

};

@Override
public FunctionIdentifier getIdentifier() {
return BuiltinFunctions.ARRAY_REVERSE;
}

@Override
public void setImmutableStates(Object... states) {
inputListType = (IAType) states[0];
}

@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args)
throws AlgebricksException {
return new IScalarEvaluatorFactory() {
private static final long serialVersionUID = 1L;

@Override
public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException {
return new ArrayReverseFunction(args, ctx);
}
};
}

public class ArrayReverseFunction implements IScalarEvaluator {
private final ArrayBackedValueStorage storage;
private final IScalarEvaluator listArgEval;
private final ListAccessor listAccessor;
private final IPointable listArg;

public ArrayReverseFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx)
throws HyracksDataException {
storage = new ArrayBackedValueStorage();
listArg = new VoidPointable();
listArgEval = args[0].createScalarEvaluator(ctx);
listAccessor = new ListAccessor();
}

@Override
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
// get the list argument and make sure it's a list
listArgEval.evaluate(tuple, listArg);
byte listArgType = listArg.getByteArray()[listArg.getStartOffset()];

// create the new list with the same type as the input list
IAsterixListBuilder listBuilder;
if (listArgType == ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG) {
listBuilder = new OrderedListBuilder();
} else if (listArgType == ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG) {
listBuilder = new UnorderedListBuilder();
} else {
PointableHelper.setNull(result);
return;
}

listBuilder.reset((AbstractCollectionType) inputListType);
listAccessor.reset(listArg.getByteArray(), listArg.getStartOffset());
try {
// get the list items in reverse and append to the new list
for (int i = listAccessor.size() - 1; i >= 0; i--) {
storage.reset();
listAccessor.writeItem(i, storage.getDataOutput());
listBuilder.addItem(storage);
}
storage.reset();
listBuilder.write(storage.getDataOutput(), true);
result.set(storage);
} catch (IOException e) {
throw HyracksDataException.create(e);
}
}
}
}
Expand Up @@ -145,6 +145,7 @@
import org.apache.asterix.runtime.evaluators.functions.AnyCollectionMemberDescriptor;
import org.apache.asterix.runtime.evaluators.functions.ArrayAppendDescriptor;
import org.apache.asterix.runtime.evaluators.functions.ArrayPositionDescriptor;
import org.apache.asterix.runtime.evaluators.functions.ArrayReverseDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CastTypeDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CastTypeLaxDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CheckUnknownDescriptor;
Expand Down Expand Up @@ -374,6 +375,7 @@ public static FunctionCollection createDefaultFunctionCollection() {
// array functions
fc.addGenerated(ArrayAppendDescriptor.FACTORY);
fc.addGenerated(ArrayPositionDescriptor.FACTORY);
fc.addGenerated(ArrayReverseDescriptor.FACTORY);

// unnesting functions
fc.add(TidRunningAggregateDescriptor.FACTORY);
Expand Down

0 comments on commit 6b31f73

Please sign in to comment.