1
0
Fork 0

Merge branch 'devel' of ssh://github.com/ArangoDB/ArangoDB into devel

This commit is contained in:
Max Neunhoeffer 2016-10-20 11:34:56 +02:00
commit 82097d7999
5 changed files with 191 additions and 27 deletions

View File

@ -15,6 +15,9 @@ devel
* fixed issue #2075
* added AQL function `DISTANCE` to calculate the distance between two arbitrary
coordinates (haversine formula)
* rewrote scheduler and dispatcher based on boost::asio
parameters changed:
@ -36,39 +39,44 @@ devel
* fixed issue #2071
make the AQL query optimizer inject filter condition expressions referred to by variables during filter condition aggregation.
for example, in the following query
make the AQL query optimizer inject filter condition expressions referred to
by variables during filter condition aggregation.
For example, in the following query
FOR doc IN collection
LET cond1 = (doc.value == 1)
LET cond2 = (doc.value == 2)
FILTER cond1 || cond2
RETURN { doc, cond1, cond2 }
LET cond1 = (doc.value == 1)
LET cond2 = (doc.value == 2)
FILTER cond1 || cond2
RETURN { doc, cond1, cond2 }
the optimizer will now inject the conditions for `cond1` and `cond2` into the filter condition `cond1 || cond2`, expanding it to
`(doc.value == 1) || (doc.value == 2)` and making these conditions available for index searching.
the optimizer will now inject the conditions for `cond1` and `cond2` into the filter
condition `cond1 || cond2`, expanding it to `(doc.value == 1) || (doc.value == 2)`
and making these conditions available for index searching.
note that the optimizer previously already injected some conditions into other conditions, but only if the variable that defined
the condition was not used elsewhere. for example, the filter condition in the query
Note that the optimizer previously already injected some conditions into other
conditions, but only if the variable that defined the condition was not used
elsewhere. For example, the filter condition in the query
FOR doc IN collection
LET cond = (doc.value == 1)
FILTER cond
RETURN { doc }
LET cond = (doc.value == 1)
FILTER cond
RETURN { doc }
already got optimized before because `cond` was only used once in the query and the optimizer decided to inject it into the
place where it was used.
already got optimized before because `cond` was only used once in the query and
the optimizer decided to inject it into the place where it was used.
this only worked for variables that were referred to once in the query. when a variable was used multiple times, the condition
was not injected as in the following query
This only worked for variables that were referred to once in the query.
When a variable was used multiple times, the condition was not injected as
in the following query:
FOR doc IN collection
LET cond = (doc.value == 1)
FILTER cond
RETURN { doc, cond }
the fix for #2070 now will enable this optimization so that the query can use an index on `doc.value` if available.
LET cond = (doc.value == 1)
FILTER cond
RETURN { doc, cond }
The fix for #2070 now will enable this optimization so that the query can
use an index on `doc.value` if available.
* changed behavior of AQL array comparison operators for empty arrays:
* `ALL` and `ANY` now always return `false` when the left-hand operand is an
empty array. The behavior for non-empty arrays does not change:

View File

@ -70,9 +70,35 @@ There is no guaranteed order in which the documents are returned.
!SECTION Geo utility functions
The following helper functions do **not use any geo index**. It is advisable to use
them in combination with index-accelerated geo functions to limit the number of
calls to the non-accelerated functions because of their computational costs.
The following helper functions do **not use any geo index**. On large datasets,
it is advisable to use them in combination with index-accelerated geo functions
to limit the number of calls to these non-accelerated functions because of their
computational costs.
!SUBSECTION DISTANCE()
`DISTANCE(latitude1, longitude1, latitude2, longitude2) → distance`
Calculate the distance between two arbitrary coordinates in meters (as birds
would fly). The value is computed using the haversine formula, which is based
on a spherical Earth model. It's fast to compute and is accurate to around 0.3%,
which is sufficient for most use cases such as location-aware services.
- **latitude1** (number): the latitude portion of the first coordinate
- **longitude1** (number): the longitude portion of the first coordinate
- **latitude2** (number): the latitude portion of the second coordinate
- **longitude2** (number): the longitude portion of the second coordinate
- returns **distance** (number): the distance between both coordinates in meters
```js
// Distance between Brandenburg Gate (Berlin) and ArangoDB headquarters (Cologne)
DISTANCE(52.5163, 13.3777, 50.9322, 6.94) // 476918.89688380965 (~477km)
// Sort a small number of documents based on distance to Central Park (New York)
FOR doc IN documentSubset // e.g. documents returned by a traversal
SORT DISTANCE(doc.latitude, doc.longitude, 40.78, -73.97)
RETURN doc
```
!SUBSECTION IS_IN_POLYGON()

View File

@ -3579,7 +3579,7 @@ testFuncs.endpoints = function(options) {
return {
status: true,
skipped: true,
}
};
} else {
let instanceInfo = startInstance('tcp', Object.assign(options, {useReconnect: true}), {
'server.endpoint': endpoint,

View File

@ -1,4 +1,4 @@
/* global describe, it, beforeEach, afterEach*/
/* global db, describe, it, beforeEach, afterEach*/
'use strict';
// //////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,130 @@
/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global AQL_EXECUTE, assertEqual */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, geo queries
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Simran Brucherseifer
/// @author Copyright 2016, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var internal = require("internal");
var errors = internal.errors;
var db = require("@arangodb").db;
var helper = require("@arangodb/aql-helper");
var assertQueryError = helper.assertQueryError;
var assertQueryWarningAndNull = helper.assertQueryWarningAndNull;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function distanceSuite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test DISTANCE function
////////////////////////////////////////////////////////////////////////////////
testDistance1 : function () {
var co1 = { lat: 52.5163, lon: 13.3777, _key: "BrandenburgGate" };
var co2 = { lat: 50.9322, lon: 6.94, _key: "ArangoHQ" };
var query = "DISTANCE(" + co1.lat + "," + co1.lon + "," + co2.lat + "," + co2.lon + ")";
var expected = [ 476918.89688380965 ]; // Vincenty's formula: 477.47 km
var actual = AQL_EXECUTE("RETURN " + query).json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(" + query + ")").json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(V8(" + query + "))").json;
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test DISTANCE function
////////////////////////////////////////////////////////////////////////////////
testDistance2 : function () {
var co1 = { lat: 40.78, lon: -73.97, _key: "CentralPark" };
var co2 = { lat: 34.05, lon: -118.25, _key: "LosAngeles" };
var query = "DISTANCE(" + co1.lat + "," + co1.lon + "," + co2.lat + "," + co2.lon + ")";
var expected = [ 3938926.7382122413 ]; // Vincenty's formula: 3943.29 km
var actual = AQL_EXECUTE("RETURN " + query).json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(" + query + ")").json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(V8(" + query + "))").json;
assertEqual(expected, actual); },
////////////////////////////////////////////////////////////////////////////////
/// @brief test DISTANCE function
////////////////////////////////////////////////////////////////////////////////
testDistance3 : function () {
var co1 = { lat: 0, lon: 0, _key: "zeroPoint" };
var co2 = { lat: 0, lon: 180, _key: "otherSideOfGLobe" };
var query = "DISTANCE(" + co1.lat + "," + co1.lon + "," + co2.lat + "," + co2.lon + ")";
var expected = [ 20015086.79602057 ]; // Half of equatorial circumference (WGS 84): 20037.5085 km
var actual = AQL_EXECUTE("RETURN " + query).json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(" + query + ")").json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(V8(" + query + "))").json;
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid DISTANCE arguments
////////////////////////////////////////////////////////////////////////////////
testDistanceInvalid : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE()");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0 )");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0, 0 )");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0 )");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0, 0, 0 )");
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0, \"foo\" )");
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0, [ 1, 2, 3 ] )");
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(distanceSuite);
return jsunity.done();