Skip to content

Commit

Permalink
[NO ISSUE][FUN] Implement array_contains() 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_contains() takes an input list and a value
and returns true if the value is present in the list.
array_contains(list, val). An error is thrown if
val is object or list.

Change-Id: Ib0222ebdb4dcaaab696ebe23973be8b2347da64b
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2729
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 westmann committed Jun 28, 2018
1 parent d954c47 commit 9c9ed80
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 68 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,34 @@
/*
* 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_contains(t.`referred-topics`, "speed") from TweetMessages t order by t.tweetid),
"t2": (select array_contains([3,8,98,40], 8)),
"t3": (select array_contains([3,8,98,40], 40.0)),
"t4": (select array_contains([3,8,98,40], -3)),
"t5": (select array_contains([3,"sth",98,40], 98)),
"t6": (select array_contains([3,8,98,40], null)),
"t7": (select array_contains([3,8,98,40], missing)),
"t8": (select array_contains(missing, 6)),
"t9": (select array_contains(null, 6)),
"t10": (select array_contains(5, "sth")),
"t11": (select array_contains([5, {"id":77}, "sth"], "sth"))
};
@@ -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;

select array_contains([5,1,9], [2,3]);
@@ -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;

select array_contains([5,{"id": 5},9], {"id": 5});
@@ -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": false }, { "$1": false }, { "$1": false }, { "$1": false }, { "$1": false }, { "$1": true }, { "$1": false }, { "$1": true }, { "$1": false }, { "$1": false }, { "$1": false }, { "$1": false } ], "t2": [ { "$2": true } ], "t3": [ { "$3": true } ], "t4": [ { "$4": false } ], "t5": [ { "$5": true } ], "t6": [ { "$6": null } ], "t7": [ { } ], "t8": [ { } ], "t9": [ { "$9": null } ], "t10": [ { "$10": null } ], "t11": [ { "$11": true } ] }
Expand Up @@ -1000,6 +1000,13 @@
<output-dir compare="Text">array_reverse</output-dir>
</compilation-unit>
</test-case>
<test-case FilePath="array_fun">
<compilation-unit name="array_contains">
<output-dir compare="Text">array_contains</output-dir>
<expected-error>HYR0115: Cannot compare non-primitive values (in line 22, at column 8)</expected-error>
<expected-error>HYR0115: Cannot compare non-primitive values (in line 22, at column 8)</expected-error>
</compilation-unit>
</test-case>
</test-group>
<test-group name="boolean">
<test-case FilePath="boolean">
Expand Down
Expand Up @@ -190,6 +190,8 @@ public enum SpatialFilterKind {
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-position", 2);
public static final FunctionIdentifier ARRAY_REVERSE =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-reverse", 1);
public static final FunctionIdentifier ARRAY_CONTAINS =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-contains", 2);

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

// objects
addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true);
Expand Down
@@ -0,0 +1,109 @@
/*
* 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 static org.apache.asterix.om.types.EnumDeserializer.ATYPETAGDESERIALIZER;

import java.io.IOException;

import org.apache.asterix.dataflow.data.nontagged.comparators.AObjectAscBinaryComparatorFactory;
import org.apache.asterix.om.base.AMutableInt32;
import org.apache.asterix.runtime.evaluators.common.ListAccessor;
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.dataflow.value.IBinaryComparator;
import org.apache.hyracks.api.exceptions.ErrorCode;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.api.exceptions.SourceLocation;
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;

public abstract class AbstractArraySearchEval implements IScalarEvaluator {
private final IPointable listArg;
private final IPointable searchedValueArg;
private final IScalarEvaluator listEval;
private final IScalarEvaluator searchedValueEval;
private final IBinaryComparator comp;
private final ListAccessor listAccessor;
private final SourceLocation sourceLocation;
protected final AMutableInt32 intValue;
protected final ArrayBackedValueStorage storage;

public AbstractArraySearchEval(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx, SourceLocation sourceLoc)
throws HyracksDataException {
storage = new ArrayBackedValueStorage();
listArg = new VoidPointable();
searchedValueArg = new VoidPointable();
listEval = args[0].createScalarEvaluator(ctx);
searchedValueEval = args[1].createScalarEvaluator(ctx);
comp = AObjectAscBinaryComparatorFactory.INSTANCE.createBinaryComparator();
listAccessor = new ListAccessor();
intValue = new AMutableInt32(-1);
sourceLocation = sourceLoc;
}

@Override
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
// 1st arg: list
listEval.evaluate(tuple, listArg);
byte[] listBytes = listArg.getByteArray();
int listOffset = listArg.getStartOffset();

// 2nd arg: value to search for
searchedValueEval.evaluate(tuple, searchedValueArg);
byte[] valueBytes = searchedValueArg.getByteArray();
int valueOffset = searchedValueArg.getStartOffset();
int valueLength = searchedValueArg.getLength();

// for now, we don't support deep equality of object/lists. Throw an error if the value is of these types
if (ATYPETAGDESERIALIZER.deserialize(valueBytes[valueOffset]).isDerivedType()) {
throw HyracksDataException.create(ErrorCode.CANNOT_COMPARE_COMPLEX, sourceLocation);
}

if (!ATYPETAGDESERIALIZER.deserialize(listBytes[listOffset]).isListType()) {
PointableHelper.setNull(result);
return;
}

// initialize variables; -1 = value not found
intValue.setValue(-1);
listAccessor.reset(listBytes, listOffset);
int numItems = listAccessor.size();

try {
for (int i = 0; i < numItems; i++) {
storage.reset();
listAccessor.writeItem(i, storage.getDataOutput());
if (comp.compare(storage.getByteArray(), storage.getStartOffset(), storage.getLength(), valueBytes,
valueOffset, valueLength) == 0) {
intValue.setValue(i);
break;
}
}
processResult(intValue, result);
} catch (IOException e) {
throw HyracksDataException.create(e);
}
}

protected abstract void processResult(AMutableInt32 intValue, IPointable result) throws HyracksDataException;
}

0 comments on commit 9c9ed80

Please sign in to comment.