!CHAPTER Features and Improvements The following list shows in detail which features have been added or improved in ArangoDB 3.1. ArangoDB 3.1 also contains several bugfixes that are not listed here. !SECTION Communication Layer ArangoDB up to 3.0 used [libev](http://software.schmorp.de/pkg/libev.html) for the communication layer. ArangoDB starting from 3.1 uses [Boost ASIO](www.boost.org). A few options have changed concerning communication, please checkout [Incompatible changes in 3.1](ReleaseNotes/UpgradingChanges31.html). !SECTION AQL !SUBSECTION Functions added The following AQL functions have been added in 3.1: - *OUTERSECTION(array1, array2, ..., arrayn)*: returns the values that occur only once across all arrays specified. - *DISTANCE(lat1, lon1, lat2, lon2)*: returns the distance between the two coordinates specified by *(lat1, lon1)* and *(lat2, lon2)*. The distance is calculated using the haversine formula. - *JSON_STRINGIFY(value)*: returns a JSON string representation of the value. - *JSON_PARSE(value)*: converts a JSON-encoded string into a regular object !SUBSECTION Index usage in traversals 3.1 allows AQL traversals to use other indexes than just the edge index. Traversals with filters on edges can now make use of more specific indexes. For example, the query FOR v, e, p IN 2 OUTBOUND @start @@edge FILTER p.edges[0].foo == "bar" RETURN [v, e, p] may use a hash index on `["_from", "foo"]` instead of the edge index on just `["_from"]`. !SUBSECTION Optimizer improvements 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 } 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 FOR doc IN collection 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. 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 } 3.1 allows using this condition so that the query can use an index on `doc.value` (if such index exists). !SUBSECTION Miscellaneous improvements The performance of the `[*]` operator was improved for cases in which this operator did not use any filters, projections and/or offset/limits. !SECTION Audit Log Audit logging has been added, see [Auditing](Auditing/index.html). !SECTION Client tools Added option `--skip-lines` for arangoimp This allows skipping the first few lines from the import file in case the CSV or TSV import are used and some initial lines should be skipped from the input.