update version
Change-Id: Iacd392d2659256589eb73c47403c00af936e26a8
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1466
Reviewed-by: Michael Blow <mblow@apache.org>
diff --git a/docs/0.9.0/aql/externaldata.html b/docs/0.9.0/aql/externaldata.html
new file mode 100644
index 0000000..c065ab3
--- /dev/null
+++ b/docs/0.9.0/aql/externaldata.html
@@ -0,0 +1,737 @@
+<!DOCTYPE html>
+<!--
+ | Generated by Apache Maven Doxia at 2017-01-24
+ | Rendered using Apache Maven Fluido Skin 1.3.0
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="Date-Revision-yyyymmdd" content="20170124" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>AsterixDB – Accessing External Data in AsterixDB</title>
+ <link rel="stylesheet" href="../css/apache-maven-fluido-1.3.0.min.css" />
+ <link rel="stylesheet" href="../css/site.css" />
+ <link rel="stylesheet" href="../css/print.css" media="print" />
+
+
+ <script type="text/javascript" src="../js/apache-maven-fluido-1.3.0.min.js"></script>
+
+
+
+<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-41536543-1', 'uci.edu');
+ ga('send', 'pageview');</script>
+
+ </head>
+ <body class="topBarDisabled">
+
+
+
+
+ <div class="container-fluid">
+ <div id="banner">
+ <div class="pull-left">
+ <a href=".././" id="bannerLeft">
+ <img src="../images/asterixlogo.png" alt="AsterixDB"/>
+ </a>
+ </div>
+ <div class="pull-right"> </div>
+ <div class="clear"><hr/></div>
+ </div>
+
+ <div id="breadcrumbs">
+ <ul class="breadcrumb">
+
+
+ <li id="publishDate">Last Published: 2017-01-24</li>
+
+
+
+ <li id="projectVersion" class="pull-right">Version: 0.9.0</li>
+
+ <li class="divider pull-right">|</li>
+
+ <li class="pull-right"> <a href="../index.html" title="Documentation Home">
+ Documentation Home</a>
+ </li>
+
+ </ul>
+ </div>
+
+
+ <div class="row-fluid">
+ <div id="leftColumn" class="span3">
+ <div class="well sidebar-nav">
+
+
+ <ul class="nav nav-list">
+ <li class="nav-header">Get Started - Installation</li>
+
+ <li>
+
+ <a href="../ncservice.html" title="Option 1: using NCService">
+ <i class="none"></i>
+ Option 1: using NCService</a>
+ </li>
+
+ <li>
+
+ <a href="../install.html" title="Option 2: using Managix">
+ <i class="none"></i>
+ Option 2: using Managix</a>
+ </li>
+
+ <li>
+
+ <a href="../yarn.html" title="Option 3: using YARN">
+ <i class="none"></i>
+ Option 3: using YARN</a>
+ </li>
+ <li class="nav-header">AsterixDB Primer</li>
+
+ <li>
+
+ <a href="../sqlpp/primer-sqlpp.html" title="Option 1: using SQL++">
+ <i class="none"></i>
+ Option 1: using SQL++</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/primer.html" title="Option 2: using AQL">
+ <i class="none"></i>
+ Option 2: using AQL</a>
+ </li>
+ <li class="nav-header">Data Model</li>
+
+ <li>
+
+ <a href="../datamodel.html" title="The Asterix Data Model">
+ <i class="none"></i>
+ The Asterix Data Model</a>
+ </li>
+ <li class="nav-header">Queries - SQL++</li>
+
+ <li>
+
+ <a href="../sqlpp/manual.html" title="The SQL++ Query Language">
+ <i class="none"></i>
+ The SQL++ Query Language</a>
+ </li>
+
+ <li>
+
+ <a href="../sqlpp/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Queries - AQL</li>
+
+ <li>
+
+ <a href="../aql/manual.html" title="The Asterix Query Language (AQL)">
+ <i class="none"></i>
+ The Asterix Query Language (AQL)</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Advanced Features</li>
+
+ <li>
+
+ <a href="../aql/similarity.html" title="Support of Similarity Queries">
+ <i class="none"></i>
+ Support of Similarity Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/fulltext.html" title="Support of Full-text Queries">
+ <i class="none"></i>
+ Support of Full-text Queries</a>
+ </li>
+
+ <li class="active">
+
+ <a href="#"><i class="none"></i>Accessing External Data</a>
+ </li>
+
+ <li>
+
+ <a href="../feeds/tutorial.html" title="Support for Data Ingestion">
+ <i class="none"></i>
+ Support for Data Ingestion</a>
+ </li>
+
+ <li>
+
+ <a href="../udf.html" title="User Defined Functions">
+ <i class="none"></i>
+ User Defined Functions</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/filters.html" title="Filter-Based LSM Index Acceleration">
+ <i class="none"></i>
+ Filter-Based LSM Index Acceleration</a>
+ </li>
+ <li class="nav-header">API/SDK</li>
+
+ <li>
+
+ <a href="../api.html" title="HTTP API">
+ <i class="none"></i>
+ HTTP API</a>
+ </li>
+ </ul>
+
+
+
+ <hr class="divider" />
+
+ <div id="poweredBy">
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <a href=".././" title="AsterixDB" class="builtBy">
+ <img class="builtBy" alt="AsterixDB" src="../images/asterixlogo.png" />
+ </a>
+ </div>
+ </div>
+ </div>
+
+
+ <div id="bodyColumn" class="span9" >
+
+ <!-- ! 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.
+ ! --><h1>Accessing External Data in AsterixDB</h1>
+<div class="section">
+<h2><a name="Table_of_Contents"></a><a name="toc" id="toc">Table of Contents</a></h2>
+
+<ul>
+
+<li><a href="#Introduction">Introduction</a></li>
+
+<li><a href="#IntroductionAdapterForAnExternalDataset">Adapter for an External Dataset</a></li>
+
+<li><a href="#BuiltinAdapters">Builtin Adapters</a></li>
+
+<li><a href="#IntroductionCreatingAnExternalDataset">Creating an External Dataset</a></li>
+
+<li><a href="#WritingQueriesAgainstAnExternalDataset">Writing Queries against an External Dataset</a></li>
+
+<li><a href="#BuildingIndexesOverExternalDatasets">Building Indexes over External Datasets</a></li>
+
+<li><a href="#ExternalDataSnapshot">External Data Snapshots</a></li>
+
+<li><a href="#FAQ">Frequently Asked Questions</a></li>
+</ul></div>
+<div class="section">
+<h2><a name="Introduction_Back_to_TOC"></a><a name="Introduction" id="Introduction">Introduction</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>Data that needs to be processed by AsterixDB could be residing outside AsterixDB storage. Examples include data files on a distributed file system such as HDFS or on the local file system of a machine that is part of an AsterixDB cluster. For AsterixDB to process such data, an end-user may create a regular dataset in AsterixDB (a.k.a. an internal dataset) and load the dataset with the data. AsterixDB also supports ‘‘external datasets’’ so that it is not necessary to “load” all data prior to using it. This also avoids creating multiple copies of data and the need to keep the copies in sync.</p>
+<div class="section">
+<h3><a name="Adapter_for_an_External_Dataset_Back_to_TOC"></a><a name="IntroductionAdapterForAnExternalDataset" id="IntroductionAdapterForAnExternalDataset">Adapter for an External Dataset</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h3>
+<p>External data is accessed using wrappers (adapters in AsterixDB) that abstract away the mechanism of connecting with an external service, receiving its data and transforming the data into ADM objects that are understood by AsterixDB. AsterixDB comes with built-in adapters for common storage systems such as HDFS or the local file system.</p></div>
+<div class="section">
+<h3><a name="Builtin_Adapters_Back_to_TOC"></a><a name="BuiltinAdapters" id="BuiltinAdapters">Builtin Adapters</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h3>
+<p>AsterixDB offers a set of builtin adapters that can be used to query external data or for loading data into an internal dataset using a load statement or a data feed. Each adapter requires specifying the <tt>format</tt> of the data in order to be able to parse objects correctly. Using adapters with feeds, the parameter <tt>output-type</tt> must also be specified.</p>
+<p>Following is a listing of existing built-in adapters and their configuration parameters:</p>
+
+<ol style="list-style-type: decimal">
+
+<li><b><i>localfs</i></b>: used for reading data stored in a local filesystem in one or more of the node controllers
+
+<ul>
+
+<li><tt>path</tt>: A fully qualified path of the form <tt>host://absolute_path</tt>. Comma separated list if there are multiple directories or files</li>
+
+<li><tt>expression</tt>: A <a class="externalLink" href="https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html">regular expression</a> to match and filter against file names</li>
+ </ul></li>
+
+<li><b><i>hdfs</i></b>: used for reading data stored in an HDFS instance
+
+<ul>
+
+<li><tt>path</tt>: A fully qualified path of the form <tt>host://absolute_path</tt>. Comma separated list if there are multiple directories or files</li>
+
+<li><tt>expression</tt>: A <a class="externalLink" href="https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html">regular expression</a> to match and filter against file names</li>
+
+<li><tt>input-format</tt>: A fully qualified name or an alias for a class of HDFS input format</li>
+
+<li><tt>hdfs</tt>: The HDFS name node URL</li>
+ </ul></li>
+
+<li><b><i>socket</i></b>: used for listening to connections that sends data streams through one or more sockets
+
+<ul>
+
+<li><tt>sockets</tt>: comma separated list of sockets to listen to</li>
+
+<li><tt>address-type</tt>: either IP if the list uses IP addresses, or NC if the list uses NC names</li>
+ </ul></li>
+
+<li><b><i>socket_client</i></b>: used for connecting to one or more sockets and reading data streams
+
+<ul>
+
+<li><tt>sockets</tt>: comma separated list of sockets to connect to</li>
+ </ul></li>
+
+<li><b><i>twitter_push</i></b>: used for establishing a connection and subscribing to a twitter feed
+
+<ul>
+
+<li><tt>consumer.key</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>consumer.secret</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>access.token</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>access.token.secret</tt>: access parameter provided by twitter OAuth</li>
+ </ul></li>
+
+<li><b><i>twitter_pull</i></b>: used for polling a twitter feed for tweets based on a configurable frequency
+
+<ul>
+
+<li><tt>consumer.key</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>consumer.secret</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>access.token</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>access.token.secret</tt>: access parameter provided by twitter OAuth</li>
+
+<li><tt>query</tt>: twitter query string</li>
+
+<li><tt>interval</tt>: poll interval in seconds</li>
+ </ul></li>
+
+<li><b><i>rss</i></b>: used for reading RSS feed
+
+<ul>
+
+<li><tt>url</tt>: a comma separated list of RSS urls</li>
+ </ul></li>
+</ol></div>
+<div class="section">
+<h3><a name="Creating_an_External_Dataset_Back_to_TOC"></a><a name="IntroductionCreatingAnExternalDataset" id="IntroductionCreatingAnExternalDataset">Creating an External Dataset</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h3>
+<p>As an example we consider the Lineitem dataset from the <a class="externalLink" href="http://www.openlinksw.com/dataspace/doc/dav/wiki/Main/VOSTPCHLinkedData/tpch.sql">TPCH schema</a>. We assume that you have successfully created an AsterixDB instance following the instructions at <a href="../install.html">Installing AsterixDB Using Managix</a>. <i>For constructing an example, we assume a single machine setup..</i></p>
+<p>Similar to a regular dataset, an external dataset has an associated datatype. We shall first create the datatype associated with each object in Lineitem data. Paste the following in the query textbox on the webpage at <a class="externalLink" href="http://127.0.0.1:19001">http://127.0.0.1:19001</a> and hit ‘Execute’.</p>
+
+<div class="source">
+<div class="source">
+<pre> create dataverse ExternalFileDemo;
+ use dataverse ExternalFileDemo;
+
+ create type LineitemType as closed {
+ l_orderkey:int32,
+ l_partkey: int32,
+ l_suppkey: int32,
+ l_linenumber: int32,
+ l_quantity: double,
+ l_extendedprice: double,
+ l_discount: double,
+ l_tax: double,
+ l_returnflag: string,
+ l_linestatus: string,
+ l_shipdate: string,
+ l_commitdate: string,
+ l_receiptdate: string,
+ l_shipinstruct: string,
+ l_shipmode: string,
+ l_comment: string}
+</pre></div></div>
+<p>Here, we describe two scenarios.</p>
+<div class="section">
+<h4><a name="a1_Data_file_resides_on_the_local_file_system_of_a_host"></a>1) Data file resides on the local file system of a host</h4>
+<p>Prerequisite: The host is a part of the ASTERIX cluster.</p>
+<p>Earlier, we assumed a single machine ASTERIX setup. To satisfy the prerequisite, log-in to the machine running ASTERIX.</p>
+
+<ul>
+
+<li>Download the <a href="../data/lineitem.tbl">data file</a> to an appropriate location. We denote this location by SOURCE_PATH.</li>
+</ul>
+<p>ASTERIX provides a built-in adapter for data residing on the local file system. The adapter is referred by its alias- ‘localfs’. We create an external dataset named Lineitem and use the ‘localfs’ adapter.</p>
+
+<div class="source">
+<div class="source">
+<pre> create external dataset Lineitem(LineitemType)
+ using localfs
+</pre></div></div>
+<p>Above, the definition is not complete as we need to provide a set of parameters that are specific to the source file.</p>
+
+<table border="0" class="table table-striped">
+
+<tr class="a">
+
+<td> Parameter </td>
+
+<td> Description </td>
+</tr>
+
+<tr class="b">
+
+<td> path </td>
+
+<td> A fully qualified path of the form <tt>host://<absolute path></tt>.
+ Use a comma separated list if there are multiple files.
+ E.g. <tt>host1://<absolute path></tt>, <tt>host2://<absolute path></tt> and so forth. </td>
+</tr>
+
+<tr class="a">
+
+<td> format </td>
+
+<td> The format for the content. Use 'adm' for data in ADM (ASTERIX Data Model) or <a class="externalLink" href="http://www.json.org/">JSON</a> format. Use 'delimited-text' if fields are separated by a delimiting character (eg., CSV). </td></tr>
+
+<tr class="b">
+
+<td>delimiter</td>
+
+<td>The delimiting character in the source file if format is 'delimited text'</td>
+</tr>
+</table>
+<p>As we are using a single single machine ASTERIX instance, we use 127.0.0.1 as host in the path parameter. We <i>complete the create dataset statement</i> as follows.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse ExternalFileDemo;
+
+ create external dataset Lineitem(LineitemType)
+ using localfs
+ (("path"="127.0.0.1://SOURCE_PATH"),
+ ("format"="delimited-text"),
+ ("delimiter"="|"));
+</pre></div></div>
+<p>Please substitute SOURCE_PATH with the absolute path to the source file on the local file system.</p></div>
+<div class="section">
+<h4><a name="Common_source_of_error"></a>Common source of error</h4>
+<p>An incorrect value for the path parameter will give the following exception message when the dataset is used in a query.</p>
+
+<div class="source">
+<div class="source">
+<pre> org.apache.hyracks.algebricks.common.exceptions.AlgebricksException: org.apache.hyracks.api.exceptions.HyracksDataException: org.apache.hyracks.api.exceptions.HyracksDataException: Job failed.
+</pre></div></div>
+<p>Verify the correctness of the path parameter provided to the localfs adapter. Note that the path parameter must be an absolute path to the data file. For e.g. if you saved your file in your home directory (assume it to be /home/joe), then the path value should be</p>
+
+<div class="source">
+<div class="source">
+<pre> 127.0.0.1:///home/joe/lineitem.tbl.
+</pre></div></div>
+<p>In your web-browser, navigate to 127.0.0.1:19001 and paste the above to the query text box. Finally hit ‘Execute’.</p>
+<p>Next we move over to the the section <a href="#Writing_Queries_against_an_External_Dataset">Writing Queries against an External Dataset</a> and try a sample query against the external dataset.</p></div>
+<div class="section">
+<h4><a name="a2_Data_file_resides_on_an_HDFS_instance"></a>2) Data file resides on an HDFS instance</h4>
+<p>rerequisite: It is required that the Namenode and HDFS Datanodes are reachable from the hosts that form the AsterixDB cluster. AsterixDB provides a built-in adapter for data residing on HDFS. The HDFS adapter can be referred (in AQL) by its alias - ‘hdfs’. We can create an external dataset named Lineitem and associate the HDFS adapter with it as follows;</p>
+
+<div class="source">
+<div class="source">
+<pre> create external dataset Lineitem(LineitemType)
+ using hdfs((“hdfs”:”hdfs://localhost:54310”),(“path”:”/asterix/Lineitem.tbl”),...,(“input- format”:”rc-format”));
+</pre></div></div>
+<p>The expected parameters are described below:</p>
+
+<table border="0" class="table table-striped">
+
+<tr class="a">
+
+<td> Parameter </td>
+
+<td> Description </td>
+</tr>
+
+<tr class="b">
+
+<td> hdfs </td>
+
+<td> The HDFS URL </td>
+</tr>
+
+<tr class="a">
+
+<td> path </td>
+
+<td> The absolute path to the source HDFS file or directory. Use a comma separated list if there are multiple files or directories. </td></tr>
+
+<tr class="b">
+
+<td> input-format </td>
+
+<td> The associated input format. Use 'text-input-format' for text files , 'sequence-input-format' for hadoop sequence files, 'rc-input-format' for Hadoop Object Columnar files, or a fully qualified name of an implementation of org.apache.hadoop.mapred.InputFormat. </td>
+</tr>
+
+<tr class="a">
+
+<td> format </td>
+
+<td> The format of the input content. Use 'adm' for text data in ADM (ASTERIX Data Model) or <a class="externalLink" href="http://www.json.org/">JSON</a> format, 'delimited-text' for text delimited data that has fields separated by a delimiting character, 'binary' for other data.</td>
+</tr>
+
+<tr class="b">
+
+<td> delimiter </td>
+
+<td> The delimiting character in the source file if format is 'delimited text' </td>
+</tr>
+
+<tr class="a">
+
+<td> parser </td>
+
+<td> The parser used to parse HDFS objects if the format is 'binary'. Use 'hive- parser' for data deserialized by a Hive Serde (AsterixDB can understand deserialized Hive objects) or a fully qualified class name of user- implemented parser that implements the interface org.apache.asterix.external.input.InputParser. </td>
+</tr>
+
+<tr class="b">
+
+<td> hive-serde </td>
+
+<td> The Hive serde is used to deserialize HDFS objects if format is binary and the parser is hive-parser. Use a fully qualified name of a class implementation of org.apache.hadoop.hive.serde2.SerDe. </td>
+</tr>
+
+<tr class="a">
+
+<td> local-socket-path </td>
+
+<td> The UNIX domain socket path if local short-circuit reads are enabled in the HDFS instance</td>
+</tr>
+</table>
+<p><i>Difference between ‘input-format’ and ‘format’</i></p>
+<p><i>input-format</i>: Files stored under HDFS have an associated storage format. For example, TextInputFormat represents plain text files. SequenceFileInputFormat indicates binary compressed files. RCFileInputFormat corresponds to objects stored in a object columnar fashion. The parameter ‘input-format’ is used to distinguish between these and other HDFS input formats.</p>
+<p><i>format</i>: The parameter ‘format’ refers to the type of the data contained in the file. For example, data contained in a file could be in json or ADM format, could be in delimited-text with fields separated by a delimiting character or could be in binary format.</p>
+<p>As an example. consider the <a href="../data/lineitem.tbl">data file</a>. The file is a text file with each line representing a object. The fields in each object are separated by the ‘|’ character.</p>
+<p>We assume the HDFS URL to be <a class="externalLink" href="hdfs://localhost:54310">hdfs://localhost:54310</a>. We further assume that the example data file is copied to HDFS at a path denoted by “/asterix/Lineitem.tbl”.</p>
+<p>The complete set of parameters for our example file are as follows. ((“hdfs”=“hdfs://localhost:54310”,(“path”=“/asterix/Lineitem.tbl”),(“input-format”=“text- input-format”),(“format”=“delimited-text”),(“delimiter”=“|”))</p></div>
+<div class="section">
+<h4><a name="Using_the_Hive_Parser"></a>Using the Hive Parser</h4>
+<p>if a user wants to create an external dataset that uses hive-parser to parse HDFS objects, it is important that the datatype associated with the dataset matches the actual data in the Hive table for the correct initialization of the Hive SerDe. Here is the conversion from the supported Hive data types to AsterixDB data types:</p>
+
+<table border="0" class="table table-striped">
+
+<tr class="a">
+
+<td> Hive </td>
+
+<td> AsterixDB </td>
+</tr>
+
+<tr class="b">
+
+<td>BOOLEAN</td>
+
+<td>Boolean</td>
+</tr>
+
+<tr class="a">
+
+<td>BYTE(TINY INT)</td>
+
+<td>Int8</td>
+</tr>
+
+<tr class="b">
+
+<td>DOUBLE</td>
+
+<td>Double</td>
+</tr>
+
+<tr class="a">
+
+<td>FLOAT</td>
+
+<td>Float</td>
+</tr>
+
+<tr class="b">
+
+<td>INT</td>
+
+<td>Int32</td>
+</tr>
+
+<tr class="a">
+
+<td>LONG(BIG INT)</td>
+
+<td>Int64</td>
+</tr>
+
+<tr class="b">
+
+<td>SHORT(SMALL INT)</td>
+
+<td>Int16</td>
+</tr>
+
+<tr class="a">
+
+<td>STRING</td>
+
+<td>String</td>
+</tr>
+
+<tr class="b">
+
+<td>TIMESTAMP</td>
+
+<td>Datetime</td>
+</tr>
+
+<tr class="a">
+
+<td>DATE</td>
+
+<td>Date</td>
+</tr>
+
+<tr class="b">
+
+<td>STRUCT</td>
+
+<td>Nested Object</td>
+</tr>
+
+<tr class="a">
+
+<td>LIST</td>
+
+<td>OrderedList or UnorderedList</td>
+</tr>
+</table></div>
+<div class="section">
+<h4><a name="Examples_of_dataset_definitions_for_external_datasets"></a>Examples of dataset definitions for external datasets</h4>
+<p><i>Example 1</i>: We can modify the create external dataset statement as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> create external dataset Lineitem('LineitemType)
+ using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/Lineitem.tbl"),("input-format"="text- input-format"),("format"="delimited-text"),("delimiter"="|"));
+</pre></div></div>
+<p><i>Example 2</i>: Here, we create an external dataset of lineitem objects stored in sequence files that has content in ADM format:</p>
+
+<div class="source">
+<div class="source">
+<pre> create external dataset Lineitem('LineitemType)
+ using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/SequenceLineitem.tbl"),("input- format"="sequence-input-format"),("format"="adm"));
+</pre></div></div>
+<p><i>Example 3</i>: Here, we create an external dataset of lineitem objects stored in object-columnar files that has content in binary format parsed using hive-parser with hive ColumnarSerde:</p>
+
+<div class="source">
+<div class="source">
+<pre> create external dataset Lineitem('LineitemType)
+ using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/RCLineitem.tbl"),("input-format"="rc-input-format"),("format"="binary"),("parser"="hive-parser"),("hive- serde"="org.apache.hadoop.hive.serde2.columnar.ColumnarSerde"));
+</pre></div></div></div></div></div>
+<div class="section">
+<h2><a name="Writing_Queries_against_an_External_Dataset_Back_to_TOC"></a><a name="WritingQueriesAgainstAnExternalDataset" id="WritingQueriesAgainstAnExternalDataset">Writing Queries against an External Dataset</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>You may write AQL queries against an external dataset in exactly the same way that queries are written against internal datasets. The following is an example of an AQL query that applies a filter and returns an ordered result.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse ExternalFileDemo;
+
+ for $c in dataset('Lineitem')
+ where $c.l_orderkey <= 3
+ order by $c.l_orderkey, $c.l_linenumber
+ return $c
+</pre></div></div></div>
+<div class="section">
+<h2><a name="Building_Indexes_over_External_Datasets_Back_to_TOC"></a><a name="BuildingIndexesOverExternalDatasets" id="BuildingIndexesOverExternalDatasets">Building Indexes over External Datasets</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>AsterixDB supports building B-Tree and R-Tree indexes over static data stored in the Hadoop Distributed File System. To create an index, first create an external dataset over the data as follows</p>
+
+<div class="source">
+<div class="source">
+<pre> create external dataset Lineitem(LineitemType)
+ using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/Lineitem.tbl"),("input-format"="text-input- format"),("format"="delimited-text"),("delimiter"="|"));
+</pre></div></div>
+<p>You can then create a B-Tree index on this dataset instance as if the dataset was internally stored as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> create index PartkeyIdx on Lineitem(l_partkey);
+</pre></div></div>
+<p>You could also create an R-Tree index as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> create index IndexName on DatasetName(attribute-name) type rtree;
+</pre></div></div>
+<p>After building the indexes, the AsterixDB query compiler can use them to access the dataset and answer queries in a more cost effective manner. AsterixDB can read all HDFS input formats, but indexes over external datasets can currently be built only for HDFS datasets with ‘text-input-format’, ‘sequence-input-format’ or ‘rc-input-format’.</p></div>
+<div class="section">
+<h2><a name="External_Data_Snapshots_Back_to_TOC"></a><a name="ExternalDataSnapshots" id="ExternalDataSnapshots">External Data Snapshots</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>An external data snapshot represents the status of a dataset’s files in HDFS at a point in time. Upon creating the first index over an external dataset, AsterixDB captures and stores a snapshot of the dataset in HDFS. Only objects present at the snapshot capture time are indexed, and any additional indexes created afterwards will only contain data that was present at the snapshot capture time thus preserving consistency across all indexes of a dataset. To update all indexes of an external dataset and advance the snapshot time to be the present time, a user can use the refresh external dataset command as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> refresh external dataset DatasetName;
+</pre></div></div>
+<p>After a refresh operation commits, all of the dataset’s indexes will reflect the status of the data as of the new snapshot capture time.</p></div>
+<div class="section">
+<h2><a name="Frequently_Asked_Questions_Back_to_TOC"></a><a name="FAQ" id="FAQ">Frequently Asked Questions</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>Q. I added data to my dataset in HDFS, Will the dataset indexes in AsterixDB be updated automatically?</p>
+<p>A. No, you must use the refresh external dataset statement to make the indexes aware of any changes in the dataset files in HDFS.</p>
+<p>Q. Why doesn’t AsterixDB update external indexes automatically?</p>
+<p>A. Since external data is managed by other users/systems with mechanisms that are system dependent, AsterixDB has no way of knowing exactly when data is added or deleted in HDFS, so the responsibility of refreshing indexes are left to the user. A user can use internal datasets for which AsterixDB manages the data and its indexes.</p>
+<p>Q. I created an index over an external dataset and then added some data to my HDFS dataset. Will a query that uses the index return different results from a query that doesn’t use the index?</p>
+<p>A. No, queries’ results are access path independent and the stored snapshot is used to determines which data are going to be included when processing queries.</p>
+<p>Q. I created an index over an external dataset and then deleted some of my dataset’s files in HDFS, Will indexed data access still return the objects in deleted files?</p>
+<p>A. No. When AsterixDB accesses external data, with or without the use of indexes, it only access files present in the file system at runtime.</p>
+<p>Q. I submitted a refresh command on a an external dataset and a failure occurred, What has happened to my indexes?</p>
+<p>A. External Indexes Refreshes are treated as a single transaction. In case of a failure, a rollback occurs and indexes are restored to their previous state. An error message with the cause of failure is returned to the user.</p>
+<p>Q. I was trying to refresh an external dataset while some queries were accessing the data using index access method. Will the queries be affected by the refresh operation?</p>
+<p>A. Queries have access to external dataset indexes state at the time where the queries are submitted. A query that was submitted before a refresh commits will only access data under the snapshot taken before the refresh; queries that are submitted after the refresh commits will access data under the snapshot taken after the refresh.</p>
+<p>Q. What happens when I try to create an additional index while a refresh operation is in progress or vice versa?</p>
+<p>A. The create index operation will wait until the refresh commits or aborts and then the index will be built according to the external data snapshot at the end of the refresh operation. Creating indexes and refreshing datasets are mutually exclusive operations and will not be run in parallel. Multiple indexes can be created in parallel, but not multiple refresh operations.</p></div>
+ </div>
+ </div>
+ </div>
+
+ <hr/>
+
+ <footer>
+ <div class="container-fluid">
+ <div class="row span12">Copyright © 2017
+ <a href="https://www.apache.org/">The Apache Software Foundation</a>.
+ All Rights Reserved.
+
+ </div>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<div class="row-fluid">Apache AsterixDB, AsterixDB, Apache, the Apache
+ feather logo, and the Apache AsterixDB project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.</div>
+
+
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/docs/0.9.0/aql/filters.html b/docs/0.9.0/aql/filters.html
new file mode 100644
index 0000000..94f3be0
--- /dev/null
+++ b/docs/0.9.0/aql/filters.html
@@ -0,0 +1,292 @@
+<!DOCTYPE html>
+<!--
+ | Generated by Apache Maven Doxia at 2017-01-24
+ | Rendered using Apache Maven Fluido Skin 1.3.0
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="Date-Revision-yyyymmdd" content="20170124" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>AsterixDB – Filter-Based LSM Index Acceleration</title>
+ <link rel="stylesheet" href="../css/apache-maven-fluido-1.3.0.min.css" />
+ <link rel="stylesheet" href="../css/site.css" />
+ <link rel="stylesheet" href="../css/print.css" media="print" />
+
+
+ <script type="text/javascript" src="../js/apache-maven-fluido-1.3.0.min.js"></script>
+
+
+
+<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-41536543-1', 'uci.edu');
+ ga('send', 'pageview');</script>
+
+ </head>
+ <body class="topBarDisabled">
+
+
+
+
+ <div class="container-fluid">
+ <div id="banner">
+ <div class="pull-left">
+ <a href=".././" id="bannerLeft">
+ <img src="../images/asterixlogo.png" alt="AsterixDB"/>
+ </a>
+ </div>
+ <div class="pull-right"> </div>
+ <div class="clear"><hr/></div>
+ </div>
+
+ <div id="breadcrumbs">
+ <ul class="breadcrumb">
+
+
+ <li id="publishDate">Last Published: 2017-01-24</li>
+
+
+
+ <li id="projectVersion" class="pull-right">Version: 0.9.0</li>
+
+ <li class="divider pull-right">|</li>
+
+ <li class="pull-right"> <a href="../index.html" title="Documentation Home">
+ Documentation Home</a>
+ </li>
+
+ </ul>
+ </div>
+
+
+ <div class="row-fluid">
+ <div id="leftColumn" class="span3">
+ <div class="well sidebar-nav">
+
+
+ <ul class="nav nav-list">
+ <li class="nav-header">Get Started - Installation</li>
+
+ <li>
+
+ <a href="../ncservice.html" title="Option 1: using NCService">
+ <i class="none"></i>
+ Option 1: using NCService</a>
+ </li>
+
+ <li>
+
+ <a href="../install.html" title="Option 2: using Managix">
+ <i class="none"></i>
+ Option 2: using Managix</a>
+ </li>
+
+ <li>
+
+ <a href="../yarn.html" title="Option 3: using YARN">
+ <i class="none"></i>
+ Option 3: using YARN</a>
+ </li>
+ <li class="nav-header">AsterixDB Primer</li>
+
+ <li>
+
+ <a href="../sqlpp/primer-sqlpp.html" title="Option 1: using SQL++">
+ <i class="none"></i>
+ Option 1: using SQL++</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/primer.html" title="Option 2: using AQL">
+ <i class="none"></i>
+ Option 2: using AQL</a>
+ </li>
+ <li class="nav-header">Data Model</li>
+
+ <li>
+
+ <a href="../datamodel.html" title="The Asterix Data Model">
+ <i class="none"></i>
+ The Asterix Data Model</a>
+ </li>
+ <li class="nav-header">Queries - SQL++</li>
+
+ <li>
+
+ <a href="../sqlpp/manual.html" title="The SQL++ Query Language">
+ <i class="none"></i>
+ The SQL++ Query Language</a>
+ </li>
+
+ <li>
+
+ <a href="../sqlpp/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Queries - AQL</li>
+
+ <li>
+
+ <a href="../aql/manual.html" title="The Asterix Query Language (AQL)">
+ <i class="none"></i>
+ The Asterix Query Language (AQL)</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Advanced Features</li>
+
+ <li>
+
+ <a href="../aql/similarity.html" title="Support of Similarity Queries">
+ <i class="none"></i>
+ Support of Similarity Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/fulltext.html" title="Support of Full-text Queries">
+ <i class="none"></i>
+ Support of Full-text Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/externaldata.html" title="Accessing External Data">
+ <i class="none"></i>
+ Accessing External Data</a>
+ </li>
+
+ <li>
+
+ <a href="../feeds/tutorial.html" title="Support for Data Ingestion">
+ <i class="none"></i>
+ Support for Data Ingestion</a>
+ </li>
+
+ <li>
+
+ <a href="../udf.html" title="User Defined Functions">
+ <i class="none"></i>
+ User Defined Functions</a>
+ </li>
+
+ <li class="active">
+
+ <a href="#"><i class="none"></i>Filter-Based LSM Index Acceleration</a>
+ </li>
+ <li class="nav-header">API/SDK</li>
+
+ <li>
+
+ <a href="../api.html" title="HTTP API">
+ <i class="none"></i>
+ HTTP API</a>
+ </li>
+ </ul>
+
+
+
+ <hr class="divider" />
+
+ <div id="poweredBy">
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <a href=".././" title="AsterixDB" class="builtBy">
+ <img class="builtBy" alt="AsterixDB" src="../images/asterixlogo.png" />
+ </a>
+ </div>
+ </div>
+ </div>
+
+
+ <div id="bodyColumn" class="span9" >
+
+ <!-- ! 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.
+ ! --><h1>Filter-Based LSM Index Acceleration</h1>
+<div class="section">
+<h2><a name="Table_of_Contents"></a><a name="toc" id="toc">Table of Contents</a></h2>
+
+<ul>
+
+<li><a href="#Motivation">Motivation</a></li>
+
+<li><a href="#FiltersInAsterixDB">Filters in AsterixDB</a></li>
+
+<li><a href="#FiltersAndMergePolicies">Filters and Merge Policies</a></li>
+</ul></div>
+<div class="section">
+<h2><a name="Motivation_Back_to_TOC"></a><a name="Motivation" id="Motivation">Motivation</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>Traditional relational databases usually employ conventional index structures such as B+ trees due to their low read latency. However, such traditional index structures use in-place writes to perform updates, resulting in costly random writes to disk. Today’s emerging applications often involve insert-intensive workloads for which the cost of random writes prohibits efficient ingestion of data. Consequently, popular NoSQL systems such as Cassandra, HBase, LevelDB, BigTable, etc. have adopted Log-Structured Merge (LSM) Trees as their storage structure. LSM-trees avoids the cost of random writes by batching updates into a component of the index that resides in main memory – an <i>in-memory component</i>. When the space occupancy of the in-memory component exceeds a specified threshold, its entries are <i>flushed</i> to disk forming a new component – a <i>disk component</i>. As disk components accumulate on disk, they are periodically merged together subject to a <i>merge policy</i> that decides when and what to merge. The benefit of the LSM-trees comes at the cost of possibly sacrificing read efficiency, but, it has been shown in previous studies that these inefficiencies can be mostly mitigated.</p>
+<p>AsterixDB has also embraced LSM-trees, not just by using them as primary indexes, but also by using the same LSM-ification technique for all of its secondary index structures. In particular, AsterixDB adopted a generic framework for converting a class of indexes (that includes conventional B+ trees, R trees, and inverted indexes) into LSM-based secondary indexes, allowing higher data ingestion rates. In fact, for certain index structures, our results have shown that using an LSM-based version of an index can be made to significantly outperform its conventional counterpart for <i>both</i> ingestion and query speed (an example of such an index being the R-tree for spatial data).</p>
+<p>Since an LSM-based index naturally partitions data into multiple disk components, it is possible, when answering certain queries, to exploit partitioning to only access some components and safely filter out the remaining components, thus reducing query times. For instance, referring to our <a href="primer.html#ADM:_Modeling_Semistructed_Data_in_AsterixDB">TinySocial</a> example, suppose a user always retrieves tweets from the <tt>TweetMessages</tt> dataset based on the <tt>send-time</tt> field (e.g., tweets posted in the last 24 hours). Since there is not a secondary index on the <tt>send-time</tt> field, the only available option for AsterixDB would be to scan the whole <tt>TweetMessages</tt> dataset and then apply the predicate as a post-processing step. However, if disk components of the primary index were tagged with the minimum and maximum timestamp values of the objects they contain, we could utilize the tagged information to directly access the primary index and prune components that do not match the query predicate. Thus, we could save substantial cost by avoiding scanning the whole dataset and only access the relevant components. We simply call such tagging information that are associated with components, filters. (Note that even if there were a secondary index on <tt>send-time</tt> field, using filters could save substantial cost by avoiding accessing the secondary index, followed by probing the primary index for every fetched entry.) Moreover, the same filtering technique can also be used with any secondary LSM index (e.g., an LSM R-tree), in case the query contains multiple predicates (e.g., spatial and temporal predicates), to obtain similar pruning power.</p></div>
+<div class="section">
+<h2><a name="Filters_in_AsterixDB_Back_to_TOC"></a><a name="FiltersInAsterixDB" id="FiltersInAsterixDB">Filters in AsterixDB</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>We have added support for LSM-based filters to all of AsterixDB’s index types. To enable the use of filters, the user must specify the filter’s key when creating a dataset, as shown below:</p>
+<div class="section">
+<div class="section">
+<h4><a name="Creating_a_Dataset_with_a_Filter"></a>Creating a Dataset with a Filter</h4>
+
+<div class="source">
+<div class="source">
+<pre> create dataset Tweets(TweetType) primary key tweetid with filter on send-time;
+</pre></div></div>
+<p>Filters can be created on any totally ordered datatype (i.e., any field that can be indexed using a B+ -tree), such as integers, doubles, floats, UUIDs, datetimes, etc.</p>
+<p>When a dataset with a filter is created, the name of the filter’s key field is persisted in the <tt>Metadata.Dataset</tt> dataset (which is the metadata dataset that stores the details of each dataset in an AsterixDB instance) so that DML operations against the dataset can recognize the existence of filters and can update them or utilize them accordingly. Creating a dataset with a filter in AsterixDB implies that the primary and all secondary indexes of that dataset will maintain filters on their disk components. Once a filtered dataset is created, the user can use the dataset normally (just like any other dataset). AsterixDB will automatically maintain the filters and will leverage them to efficiently answer queries whenever possible (i.e., when a query has predicates on the filter’s key).</p></div></div></div>
+<div class="section">
+<h2><a name="Filters_and_Merge_Policies_Back_to_TOC"></a><a name="FiltersAndMergePolicies" id="FiltersAndMergePolicies">Filters and Merge Policies</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>The AsterixDB default merge policy, the prefix merge policy, relies on component sizes and the number of components to decide which components to merge. This merge policy has proven to provide excellent performance for both ingestion and queries. However, when evaluating our filtering solution with the prefix policy, we observed a behavior that can reduce filter effectiveness. In particular, we noticed that under the prefix merge policy, the disk components of a secondary index tend to be constantly merged into a single component. This is because the prefix policy relies on a single size parameter for all of the indexes of a dataset. This parameter is typically chosen based on the sizes of the disk components of the primary index, which tend to be much larger than the sizes of the secondary indexes’ disk components. This difference caused the prefix merge policy to behave similarly to the constant merge policy (i.e., relatively poorly) when applied to secondary indexes in the sense that the secondary indexes are constantly merged into a single disk component. Consequently, the effectiveness of filters on secondary indexes was greatly reduced under the prefix-merge policy, but they were still effective when probing the primary index. Based on this behavior, we developed a new merge policy, an improved version of the prefix policy, called the correlated-prefix policy. The basic idea of this policy is that it delegates the decision of merging the disk components of all the indexes in a dataset to the primary index. When the policy decides that the primary index needs to be merged (using the same decision criteria as for the prefix policy), then it will issue successive merge requests to the I/O scheduler on behalf of all other indexes associated with the same dataset. The end result is that secondary indexes will always have the same number of disk components as their primary index under the correlated-prefix merge policy. This has improved query performance, since disk components of secondary indexes now have a much better chance of being pruned.</p></div>
+ </div>
+ </div>
+ </div>
+
+ <hr/>
+
+ <footer>
+ <div class="container-fluid">
+ <div class="row span12">Copyright © 2017
+ <a href="https://www.apache.org/">The Apache Software Foundation</a>.
+ All Rights Reserved.
+
+ </div>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<div class="row-fluid">Apache AsterixDB, AsterixDB, Apache, the Apache
+ feather logo, and the Apache AsterixDB project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.</div>
+
+
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/docs/0.9.0/aql/fulltext.html b/docs/0.9.0/aql/fulltext.html
new file mode 100644
index 0000000..d468395
--- /dev/null
+++ b/docs/0.9.0/aql/fulltext.html
@@ -0,0 +1,333 @@
+<!DOCTYPE html>
+<!--
+ | Generated by Apache Maven Doxia at 2017-01-24
+ | Rendered using Apache Maven Fluido Skin 1.3.0
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="Date-Revision-yyyymmdd" content="20170124" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>AsterixDB – AsterixDB Support of Full-text search queries</title>
+ <link rel="stylesheet" href="../css/apache-maven-fluido-1.3.0.min.css" />
+ <link rel="stylesheet" href="../css/site.css" />
+ <link rel="stylesheet" href="../css/print.css" media="print" />
+
+
+ <script type="text/javascript" src="../js/apache-maven-fluido-1.3.0.min.js"></script>
+
+
+
+<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-41536543-1', 'uci.edu');
+ ga('send', 'pageview');</script>
+
+ </head>
+ <body class="topBarDisabled">
+
+
+
+
+ <div class="container-fluid">
+ <div id="banner">
+ <div class="pull-left">
+ <a href=".././" id="bannerLeft">
+ <img src="../images/asterixlogo.png" alt="AsterixDB"/>
+ </a>
+ </div>
+ <div class="pull-right"> </div>
+ <div class="clear"><hr/></div>
+ </div>
+
+ <div id="breadcrumbs">
+ <ul class="breadcrumb">
+
+
+ <li id="publishDate">Last Published: 2017-01-24</li>
+
+
+
+ <li id="projectVersion" class="pull-right">Version: 0.9.0</li>
+
+ <li class="divider pull-right">|</li>
+
+ <li class="pull-right"> <a href="../index.html" title="Documentation Home">
+ Documentation Home</a>
+ </li>
+
+ </ul>
+ </div>
+
+
+ <div class="row-fluid">
+ <div id="leftColumn" class="span3">
+ <div class="well sidebar-nav">
+
+
+ <ul class="nav nav-list">
+ <li class="nav-header">Get Started - Installation</li>
+
+ <li>
+
+ <a href="../ncservice.html" title="Option 1: using NCService">
+ <i class="none"></i>
+ Option 1: using NCService</a>
+ </li>
+
+ <li>
+
+ <a href="../install.html" title="Option 2: using Managix">
+ <i class="none"></i>
+ Option 2: using Managix</a>
+ </li>
+
+ <li>
+
+ <a href="../yarn.html" title="Option 3: using YARN">
+ <i class="none"></i>
+ Option 3: using YARN</a>
+ </li>
+ <li class="nav-header">AsterixDB Primer</li>
+
+ <li>
+
+ <a href="../sqlpp/primer-sqlpp.html" title="Option 1: using SQL++">
+ <i class="none"></i>
+ Option 1: using SQL++</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/primer.html" title="Option 2: using AQL">
+ <i class="none"></i>
+ Option 2: using AQL</a>
+ </li>
+ <li class="nav-header">Data Model</li>
+
+ <li>
+
+ <a href="../datamodel.html" title="The Asterix Data Model">
+ <i class="none"></i>
+ The Asterix Data Model</a>
+ </li>
+ <li class="nav-header">Queries - SQL++</li>
+
+ <li>
+
+ <a href="../sqlpp/manual.html" title="The SQL++ Query Language">
+ <i class="none"></i>
+ The SQL++ Query Language</a>
+ </li>
+
+ <li>
+
+ <a href="../sqlpp/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Queries - AQL</li>
+
+ <li>
+
+ <a href="../aql/manual.html" title="The Asterix Query Language (AQL)">
+ <i class="none"></i>
+ The Asterix Query Language (AQL)</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Advanced Features</li>
+
+ <li>
+
+ <a href="../aql/similarity.html" title="Support of Similarity Queries">
+ <i class="none"></i>
+ Support of Similarity Queries</a>
+ </li>
+
+ <li class="active">
+
+ <a href="#"><i class="none"></i>Support of Full-text Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/externaldata.html" title="Accessing External Data">
+ <i class="none"></i>
+ Accessing External Data</a>
+ </li>
+
+ <li>
+
+ <a href="../feeds/tutorial.html" title="Support for Data Ingestion">
+ <i class="none"></i>
+ Support for Data Ingestion</a>
+ </li>
+
+ <li>
+
+ <a href="../udf.html" title="User Defined Functions">
+ <i class="none"></i>
+ User Defined Functions</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/filters.html" title="Filter-Based LSM Index Acceleration">
+ <i class="none"></i>
+ Filter-Based LSM Index Acceleration</a>
+ </li>
+ <li class="nav-header">API/SDK</li>
+
+ <li>
+
+ <a href="../api.html" title="HTTP API">
+ <i class="none"></i>
+ HTTP API</a>
+ </li>
+ </ul>
+
+
+
+ <hr class="divider" />
+
+ <div id="poweredBy">
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <a href=".././" title="AsterixDB" class="builtBy">
+ <img class="builtBy" alt="AsterixDB" src="../images/asterixlogo.png" />
+ </a>
+ </div>
+ </div>
+ </div>
+
+
+ <div id="bodyColumn" class="span9" >
+
+ <!-- ! 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.
+ ! --><h1>AsterixDB Support of Full-text search queries</h1>
+<div class="section">
+<h2><a name="Table_of_Contents"></a><a name="toc" id="toc">Table of Contents</a></h2>
+
+<ul>
+
+<li><a href="#Motivation">Motivation</a></li>
+
+<li><a href="#Syntax">Syntax</a></li>
+
+<li><a href="#FulltextIndex">Creating and utilizing a Full-text index</a></li>
+</ul></div>
+<div class="section">
+<h2><a name="Motivation_Back_to_TOC"></a><a name="Motivation" id="Motivation">Motivation</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>Full-Text Search (FTS) queries are widely used in applications where users need to find records that satisfy an FTS predicate, i.e., where simple string-based matching is not sufficient. These queries are important when finding documents that contain a certain keyword is crucial. FTS queries are different from substring matching queries in that FTS queries find their query predicates as exact keywords in the given string, rather than treating a query predicate as a sequence of characters. For example, an FTS query that finds “rain” correctly returns a document when it contains “rain” as a word. However, a substring-matching query returns a document whenever it contains “rain” as a substring, for instance, a document with “brain” or “training” would be returned as well.</p></div>
+<div class="section">
+<h2><a name="Syntax_Back_to_TOC"></a><a name="Syntax" id="Syntax">Syntax</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>The syntax of AsterixDB FTS follows a portion of the XQuery FullText Search syntax. Two basic forms are as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> ftcontains(Expression1, Expression2, {FullTextOption})
+ ftcontains(Expression1, Expression2)
+</pre></div></div>
+<p>For example, we can execute the following query to find tweet messages where the <tt>message-text</tt> field includes “voice” as a word. Please note that an FTS search is case-insensitive. Thus, “Voice” or “voice” will be evaluated as the same word.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $msg in dataset TweetMessages
+ where ftcontains($msg.message-text, "voice", {"mode":"any"})
+ return {"id": $msg.id}
+</pre></div></div>
+<p>The DDL and DML of TinySocial can be found in <a href="primer.html#ADM:_Modeling_Semistructed_Data_in_AsterixDB">ADM: Modeling Semistructed Data in AsterixDB</a>.</p>
+<p>The <tt>Expression1</tt> is an expression that should be evaluable as a string at runtime as in the above example where <tt>$msg.message-text</tt> is a string field. The <tt>Expression2</tt> can be a string, an (un)ordered list of string value(s), or an expression. In the last case, the given expression should be evaluable into one of the first two types, i.e., into a string value or an (un)ordered list of string value(s).</p>
+<p>The following examples are all valid expressions.</p>
+
+<div class="source">
+<div class="source">
+<pre> ... where ftcontains($msg.message-text, "sound")
+ ... where ftcontains($msg.message-text, "sound", {"mode":"any"})
+ ... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"any"})
+ ... where ftcontains($msg.message-text, {{"speed", "stand", "customization"}}, {"mode":"all"})
+ ... where ftcontains($msg.message-text, let $keyword_list := ["voice", "system"] return $keyword_list, {"mode":"all"})
+ ... where ftcontains($msg.message-text, $keyword_list, {"mode":"any"})
+</pre></div></div>
+<p>In the last example above, <tt>$keyword_list</tt> should evaluate to a string or an (un)ordered list of string value(s).</p>
+<p>The last <tt>FullTextOption</tt> parameter clarifies the given FTS request. If you omit the <tt>FullTextOption</tt> parameter, then the default value will be set for each possible option. Currently, we only have one option named <tt>mode</tt>. And as we extend the FTS feature, more options will be added. Please note that the format of <tt>FullTextOption</tt> is a record, thus you need to put the option(s) in a record <tt>{}</tt>. The <tt>mode</tt> option indicates whether the given FTS query is a conjunctive (AND) or disjunctive (OR) search request. This option can be either <tt>“any”</tt> or <tt>“all”</tt>. The default value for <tt>mode</tt> is <tt>“all”</tt>. If one specifies <tt>“any”</tt>, a disjunctive search will be conducted. For example, the following query will find documents whose <tt>message-text</tt> field contains “sound” or “system”, so a document will be returned if it contains either “sound”, “system”, or both of the keywords.</p>
+
+<div class="source">
+<div class="source">
+<pre> ... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"any"})
+</pre></div></div>
+<p>The other option parameter,<tt>“all”</tt>, specifies a conjunctive search. The following examples will find the documents whose <tt>message-text</tt> field contains both “sound” and “system”. If a document contains only “sound” or “system” but not both, it will not be returned.</p>
+
+<div class="source">
+<div class="source">
+<pre> ... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"all"})
+ ... where ftcontains($msg.message-text, ["sound", "system"])
+</pre></div></div>
+<p>Currently AsterixDB doesn’t (yet) support phrase searches, so the following query will not work.</p>
+
+<div class="source">
+<div class="source">
+<pre> ... where ftcontains($msg.message-text, "sound system", {"mode":"any"})
+</pre></div></div>
+<p>As a workaround solution, the following query can be used to achieve a roughly similar goal. The difference is that the following queries will find documents where <tt>$msg.message-text</tt> contains both “sound” and “system”, but the order and adjacency of “sound” and “system” are not checked, unlike in a phrase search. As a result, the query below would also return documents with “sound system can be installed.”, “system sound is perfect.”, or “sound is not clear. You may need to install a new system.”</p>
+
+<div class="source">
+<div class="source">
+<pre> ... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"all"})
+ ... where ftcontains($msg.message-text, ["sound", "system"])
+</pre></div></div></div>
+ </div>
+ </div>
+ </div>
+
+ <hr/>
+
+ <footer>
+ <div class="container-fluid">
+ <div class="row span12">Copyright © 2017
+ <a href="https://www.apache.org/">The Apache Software Foundation</a>.
+ All Rights Reserved.
+
+ </div>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<div class="row-fluid">Apache AsterixDB, AsterixDB, Apache, the Apache
+ feather logo, and the Apache AsterixDB project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.</div>
+
+
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/docs/0.9.0/aql/manual.html b/docs/0.9.0/aql/manual.html
new file mode 100644
index 0000000..1bdfa3b
--- /dev/null
+++ b/docs/0.9.0/aql/manual.html
@@ -0,0 +1,1075 @@
+<!DOCTYPE html>
+<!--
+ | Generated by Apache Maven Doxia at 2017-01-24
+ | Rendered using Apache Maven Fluido Skin 1.3.0
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="Date-Revision-yyyymmdd" content="20170124" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>AsterixDB – The Asterix Query Language, Version 1.0</title>
+ <link rel="stylesheet" href="../css/apache-maven-fluido-1.3.0.min.css" />
+ <link rel="stylesheet" href="../css/site.css" />
+ <link rel="stylesheet" href="../css/print.css" media="print" />
+
+
+ <script type="text/javascript" src="../js/apache-maven-fluido-1.3.0.min.js"></script>
+
+
+
+<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-41536543-1', 'uci.edu');
+ ga('send', 'pageview');</script>
+
+ </head>
+ <body class="topBarDisabled">
+
+
+
+
+ <div class="container-fluid">
+ <div id="banner">
+ <div class="pull-left">
+ <a href=".././" id="bannerLeft">
+ <img src="../images/asterixlogo.png" alt="AsterixDB"/>
+ </a>
+ </div>
+ <div class="pull-right"> </div>
+ <div class="clear"><hr/></div>
+ </div>
+
+ <div id="breadcrumbs">
+ <ul class="breadcrumb">
+
+
+ <li id="publishDate">Last Published: 2017-01-24</li>
+
+
+
+ <li id="projectVersion" class="pull-right">Version: 0.9.0</li>
+
+ <li class="divider pull-right">|</li>
+
+ <li class="pull-right"> <a href="../index.html" title="Documentation Home">
+ Documentation Home</a>
+ </li>
+
+ </ul>
+ </div>
+
+
+ <div class="row-fluid">
+ <div id="leftColumn" class="span3">
+ <div class="well sidebar-nav">
+
+
+ <ul class="nav nav-list">
+ <li class="nav-header">Get Started - Installation</li>
+
+ <li>
+
+ <a href="../ncservice.html" title="Option 1: using NCService">
+ <i class="none"></i>
+ Option 1: using NCService</a>
+ </li>
+
+ <li>
+
+ <a href="../install.html" title="Option 2: using Managix">
+ <i class="none"></i>
+ Option 2: using Managix</a>
+ </li>
+
+ <li>
+
+ <a href="../yarn.html" title="Option 3: using YARN">
+ <i class="none"></i>
+ Option 3: using YARN</a>
+ </li>
+ <li class="nav-header">AsterixDB Primer</li>
+
+ <li>
+
+ <a href="../sqlpp/primer-sqlpp.html" title="Option 1: using SQL++">
+ <i class="none"></i>
+ Option 1: using SQL++</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/primer.html" title="Option 2: using AQL">
+ <i class="none"></i>
+ Option 2: using AQL</a>
+ </li>
+ <li class="nav-header">Data Model</li>
+
+ <li>
+
+ <a href="../datamodel.html" title="The Asterix Data Model">
+ <i class="none"></i>
+ The Asterix Data Model</a>
+ </li>
+ <li class="nav-header">Queries - SQL++</li>
+
+ <li>
+
+ <a href="../sqlpp/manual.html" title="The SQL++ Query Language">
+ <i class="none"></i>
+ The SQL++ Query Language</a>
+ </li>
+
+ <li>
+
+ <a href="../sqlpp/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Queries - AQL</li>
+
+ <li class="active">
+
+ <a href="#"><i class="none"></i>The Asterix Query Language (AQL)</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Advanced Features</li>
+
+ <li>
+
+ <a href="../aql/similarity.html" title="Support of Similarity Queries">
+ <i class="none"></i>
+ Support of Similarity Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/fulltext.html" title="Support of Full-text Queries">
+ <i class="none"></i>
+ Support of Full-text Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/externaldata.html" title="Accessing External Data">
+ <i class="none"></i>
+ Accessing External Data</a>
+ </li>
+
+ <li>
+
+ <a href="../feeds/tutorial.html" title="Support for Data Ingestion">
+ <i class="none"></i>
+ Support for Data Ingestion</a>
+ </li>
+
+ <li>
+
+ <a href="../udf.html" title="User Defined Functions">
+ <i class="none"></i>
+ User Defined Functions</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/filters.html" title="Filter-Based LSM Index Acceleration">
+ <i class="none"></i>
+ Filter-Based LSM Index Acceleration</a>
+ </li>
+ <li class="nav-header">API/SDK</li>
+
+ <li>
+
+ <a href="../api.html" title="HTTP API">
+ <i class="none"></i>
+ HTTP API</a>
+ </li>
+ </ul>
+
+
+
+ <hr class="divider" />
+
+ <div id="poweredBy">
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <a href=".././" title="AsterixDB" class="builtBy">
+ <img class="builtBy" alt="AsterixDB" src="../images/asterixlogo.png" />
+ </a>
+ </div>
+ </div>
+ </div>
+
+
+ <div id="bodyColumn" class="span9" >
+
+ <!-- ! 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.
+ ! --><h1>The Asterix Query Language, Version 1.0</h1>
+<div class="section">
+<h2><a name="Table_of_Contents"></a><a name="toc" id="toc">Table of Contents</a></h2>
+
+<ul>
+
+<li><a href="#Introduction">1. Introduction</a></li>
+
+<li><a href="#Expressions">2. Expressions</a></li>
+
+<li><a href="#Statements">3. Statements</a></li>
+</ul></div>
+<div class="section">
+<h2><a name="a1._Introduction_Back_to_TOC"></a><a name="Introduction" id="Introduction">1. Introduction</a><font size="4"> <a href="#toc">[Back to TOC]</a></font></h2>
+<p>This document is intended as a reference guide to the full syntax and semantics of the Asterix Query Language (AQL), the language for talking to AsterixDB. This guide covers both the data manipulation language (DML) aspects of AQL, including its support for queries and data modification, as well as its data definition language (DDL) aspects. New AsterixDB users are encouraged to read and work through the (friendlier) guide “AsterixDB 101: An ADM and AQL Primer” before attempting to make use of this document. In addition, readers are advised to read and understand the Asterix Data Model (ADM) reference guide since a basic understanding of ADM concepts is a prerequisite to understanding AQL. In what follows, we detail the features of the AQL language in a grammar-guided manner: We list and briefly explain each of the productions in the AQL grammar, offering examples for clarity in cases where doing so seems needed or helpful.</p></div>
+<div class="section">
+<h2><a name="a2._Expressions_Back_to_TOC"></a><a name="Expressions" id="Expressions">2. Expressions</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+
+<div class="source">
+<div class="source">
+<pre>Query ::= Expression
+</pre></div></div>
+<p>An AQL query can be any legal AQL expression.</p>
+
+<div class="source">
+<div class="source">
+<pre>Expression ::= ( OperatorExpr | IfThenElse | FLWOR | QuantifiedExpression )
+</pre></div></div>
+<p>AQL is a fully composable expression language. Each AQL expression returns zero or more Asterix Data Model (ADM) instances. There are four major kinds of expressions in AQL. At the topmost level, an AQL expression can be an OperatorExpr (similar to a mathematical expression), an IfThenElse (to choose between two alternative values), a FLWOR expression (the heart of AQL, pronounced “flower expression”), or a QuantifiedExpression (which yields a boolean value). Each will be detailed as we explore the full AQL grammar.</p>
+<div class="section">
+<h3><a name="Primary_Expressions"></a>Primary Expressions</h3>
+
+<div class="source">
+<div class="source">
+<pre>PrimaryExpr ::= Literal
+ | VariableRef
+ | ParenthesizedExpression
+ | FunctionCallExpr
+ | DatasetAccessExpression
+ | ListConstructor
+ | ObjectConstructor
+</pre></div></div>
+<p>The most basic building block for any AQL expression is the PrimaryExpr. This can be a simple literal (constant) value, a reference to a query variable that is in scope, a parenthesized expression, a function call, an expression accessing the ADM contents of a dataset, a newly constructed list of ADM instances, or a newly constructed ADM object.</p>
+<div class="section">
+<h4><a name="Literals"></a>Literals</h4>
+
+<div class="source">
+<div class="source">
+<pre>Literal ::= StringLiteral
+ | IntegerLiteral
+ | FloatLiteral
+ | DoubleLiteral
+ | "null"
+ | "true"
+ | "false"
+StringLiteral ::= ("\"" (<ESCAPE_QUOT> | ~["\""])* "\"")
+ | ("\'" (<ESCAPE_APOS> | ~["\'"])* "\'")
+<ESCAPE_QUOT> ::= "\\\""
+<ESCAPE_APOS> ::= "\\\'"
+IntegerLiteral ::= <DIGITS>
+<DIGITS> ::= ["0" - "9"]+
+FloatLiteral ::= <DIGITS> ( "f" | "F" )
+ | <DIGITS> ( "." <DIGITS> ( "f" | "F" ) )?
+ | "." <DIGITS> ( "f" | "F" )
+DoubleLiteral ::= <DIGITS>
+ | <DIGITS> ( "." <DIGITS> )?
+ | "." <DIGITS>
+</pre></div></div>
+<p>Literals (constants) in AQL can be strings, integers, floating point values, double values, boolean constants, or the constant value null. The null value in AQL has “unknown” or “missing” value semantics, similar to (though not identical to) nulls in the relational query language SQL.</p>
+<p>The following are some simple examples of AQL literals. Since AQL is an expression language, each example is also a complete, legal AQL query (!).</p>
+<div class="section">
+<h5><a name="Examples"></a>Examples</h5>
+
+<div class="source">
+<div class="source">
+<pre>"a string"
+42
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Variable_References"></a>Variable References</h4>
+
+<div class="source">
+<div class="source">
+<pre>VariableRef ::= <VARIABLE>
+<VARIABLE> ::= "$" <LETTER> (<LETTER> | <DIGIT> | "_")*
+<LETTER> ::= ["A" - "Z", "a" - "z"]
+</pre></div></div>
+<p>A variable in AQL can be bound to any legal ADM value. A variable reference refers to the value to which an in-scope variable is bound. (E.g., a variable binding may originate from one of the for or let clauses of a FLWOR expression or from an input parameter in the context of an AQL function body.)</p>
+<div class="section">
+<h5><a name="Examples"></a>Examples</h5>
+
+<div class="source">
+<div class="source">
+<pre>$tweet
+$id
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Parenthesized_Expressions"></a>Parenthesized Expressions</h4>
+
+<div class="source">
+<div class="source">
+<pre>ParenthesizedExpression ::= "(" Expression ")"
+</pre></div></div>
+<p>As in most languages, an expression may be parenthesized.</p>
+<p>Since AQL is an expression language, the following example expression is actually also a complete, legal AQL query whose result is the value 2. (As such, you can have Big Fun explaining to your boss how AsterixDB and AQL can turn your 1000-node shared-nothing Big Data cluster into a $5M calculator in its spare time.)</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>( 1 + 1 )
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Function_Calls"></a>Function Calls</h4>
+
+<div class="source">
+<div class="source">
+<pre>FunctionCallExpr ::= FunctionOrTypeName "(" ( Expression ( "," Expression )* )? ")"
+</pre></div></div>
+<p>Functions are included in AQL, like most languages, as a way to package useful functionality or to componentize complicated or reusable AQL computations. A function call is a legal AQL query expression that represents the ADM value resulting from the evaluation of its body expression with the given parameter bindings; the parameter value bindings can themselves be any AQL expressions.</p>
+<p>The following example is a (built-in) function call expression whose value is 8.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>string-length("a string")
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Dataset_Access"></a>Dataset Access</h4>
+
+<div class="source">
+<div class="source">
+<pre>DatasetAccessExpression ::= "dataset" ( ( Identifier ( "." Identifier )? )
+ | ( "(" Expression ")" ) )
+Identifier ::= <IDENTIFIER> | StringLiteral
+<IDENTIFIER> ::= <LETTER> (<LETTER> | <DIGIT> | <SPECIALCHARS>)*
+<SPECIALCHARS> ::= ["$", "_", "-"]
+</pre></div></div>
+<p>Querying Big Data is the main point of AsterixDB and AQL. Data in AsterixDB reside in datasets (collections of ADM objects), each of which in turn resides in some namespace known as a dataverse (data universe). Data access in a query expression is accomplished via a DatasetAccessExpression. Dataset access expressions are most commonly used in FLWOR expressions, where variables are bound to their contents.</p>
+<p>Note that the Identifier that identifies a dataset (or any other Identifier in AQL) can also be a StringLiteral. This is especially useful to avoid conficts with AQL keywords (e.g. “dataset”, “null”, or “type”).</p>
+<p>The following are three examples of legal dataset access expressions. The first one accesses a dataset called Customers in the dataverse called SalesDV. The second one accesses the Customers dataverse in whatever the current dataverse is. The third one does the same thing as the second but uses a slightly older AQL syntax.</p>
+<div class="section">
+<h5><a name="Examples"></a>Examples</h5>
+
+<div class="source">
+<div class="source">
+<pre>dataset SalesDV.Customers
+dataset Customers
+dataset("Customers")
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Constructors"></a>Constructors</h4>
+
+<div class="source">
+<div class="source">
+<pre>ListConstructor ::= ( OrderedListConstructor | UnorderedListConstructor )
+OrderedListConstructor ::= "[" ( Expression ( "," Expression )* )? "]"
+UnorderedListConstructor ::= "{{" ( Expression ( "," Expression )* )? "}}"
+ObjectConstructor ::= "{" ( FieldBinding ( "," FieldBinding )* )? "}"
+FieldBinding ::= Expression ":" Expression
+</pre></div></div>
+<p>A major feature of AQL is its ability to construct new ADM data instances. This is accomplished using its constructors for each of the major ADM complex object structures, namely lists (ordered or unordered) and objects. Ordered lists are like JSON arrays, while unordered lists have bag (multiset) semantics. Objects are built from attributes that are field-name/field-value pairs, again like JSON. (See the AsterixDB Data Model document for more details on each.)</p>
+<p>The following examples illustrate how to construct a new ordered list with 3 items, a new unordered list with 4 items, and a new object with 2 fields, respectively. List elements can be homogeneous (as in the first example), which is the common case, or they may be heterogeneous (as in the second example). The data values and field name values used to construct lists and objects in constructors are all simply AQL expressions. Thus the list elements, field names, and field values used in constructors can be simple literals (as in these three examples) or they can come from query variable references or even arbitrarily complex AQL expressions.</p>
+<div class="section">
+<h5><a name="Examples"></a>Examples</h5>
+
+<div class="source">
+<div class="source">
+<pre>[ "a", "b", "c" ]
+
+{{ 42, "forty-two", "AsterixDB!", 3.14f }}
+
+{
+ "project name": "AsterixDB"
+ "project members": {{ "vinayakb", "dtabass", "chenli" }}
+}
+</pre></div></div></div>
+<div class="section">
+<h5><a name="Note"></a>Note</h5>
+<p>When constructing nested objects there needs to be a space between the closing braces to avoid confusion with the <tt>}}</tt> token that ends an unordered list constructor: <tt>{ "a" : { "b" : "c" }}</tt> will fail to parse while <tt>{ "a" : { "b" : "c" } }</tt> will work.</p></div></div></div>
+<div class="section">
+<h3><a name="Path_Expressions"></a>Path Expressions</h3>
+
+<div class="source">
+<div class="source">
+<pre>ValueExpr ::= PrimaryExpr ( Field | Index )*
+Field ::= "." Identifier
+Index ::= "[" ( Expression | "?" ) "]"
+</pre></div></div>
+<p>Components of complex types in ADM are accessed via path expressions. Path access can be applied to the result of an AQL expression that yields an instance of such a type, e.g., a object or list instance. For objects, path access is based on field names. For ordered lists, path access is based on (zero-based) array-style indexing. AQL also supports an “I’m feeling lucky” style index accessor, [?], for selecting an arbitrary element from an ordered list. Attempts to access non-existent fields or list elements produce a null (i.e., missing information) result as opposed to signaling a runtime error.</p>
+<p>The following examples illustrate field access for a object, index-based element access for an ordered list, and also a composition thereof.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Examples"></a>Examples</h5>
+
+<div class="source">
+<div class="source">
+<pre>({"list": [ "a", "b", "c"]}).list
+
+(["a", "b", "c"])[2]
+
+({ "list": [ "a", "b", "c"]}).list[2]
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Logical_Expressions"></a>Logical Expressions</h3>
+
+<div class="source">
+<div class="source">
+<pre>OperatorExpr ::= AndExpr ( "or" AndExpr )*
+AndExpr ::= RelExpr ( "and" RelExpr )*
+</pre></div></div>
+<p>As in most languages, boolean expressions can be built up from smaller expressions by combining them with the logical connectives and/or. Legal boolean values in AQL are true, false, and null. (Nulls in AQL are treated much like SQL treats its unknown truth value in boolean expressions.)</p>
+<p>The following is an example of a conjuctive range predicate in AQL. It will yield true if $a is bound to 4, null if $a is bound to null, and false otherwise.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>$a > 3 and $a < 5
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Comparison_Expressions"></a>Comparison Expressions</h3>
+
+<div class="source">
+<div class="source">
+<pre>RelExpr ::= AddExpr ( ( "<" | ">" | "<=" | ">=" | "=" | "!=" | "~=" ) AddExpr )?
+</pre></div></div>
+<p>AQL has the usual list of suspects, plus one, for comparing pairs of atomic values. The “plus one” is the last operator listed above, which is the “roughly equal” operator provided for similarity queries. (See the separate document on <a href="similarity.html">AsterixDB Similarity Queries</a> for more details on similarity matching.)</p>
+<p>An example comparison expression (which yields the boolean value true) is shown below.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>5 > 3
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Arithmetic_Expressions"></a>Arithmetic Expressions</h3>
+
+<div class="source">
+<div class="source">
+<pre>AddExpr ::= MultExpr ( ( "+" | "-" ) MultExpr )*
+MultExpr ::= UnaryExpr ( ( "*" | "/" | "%" | "^"| "idiv" ) UnaryExpr )*
+UnaryExpr ::= ( ( "+" | "-" ) )? ValueExpr
+</pre></div></div>
+<p>AQL also supports the usual cast of characters for arithmetic expressions. The example below evaluates to 25.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>3 ^ 2 + 4 ^ 2
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="FLWOR_Expression"></a>FLWOR Expression</h3>
+
+<div class="source">
+<div class="source">
+<pre>FLWOR ::= ( ForClause | LetClause ) ( Clause )* ("return"|"select") Expression
+Clause ::= ForClause | LetClause | WhereClause | OrderbyClause
+ | GroupClause | LimitClause | DistinctClause
+ForClause ::= ("for"|"from") Variable ( "at" Variable )? "in" ( Expression )
+LetClause ::= ("let"|"with") Variable ":=" Expression
+WhereClause ::= "where" Expression
+OrderbyClause ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )?
+ ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
+GroupClause ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )*
+ ("with"|"keeping") VariableRef ( "," VariableRef )*
+LimitClause ::= "limit" Expression ( "offset" Expression )?
+DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
+Variable ::= <VARIABLE>
+</pre></div></div>
+<p>The heart of AQL is the FLWOR (for-let-where-orderby-return) expression. The roots of this expression were borrowed from the expression of the same name in XQuery. A FLWOR expression starts with one or more clauses that establish variable bindings. A <tt>for</tt> clause binds a variable incrementally to each element of its associated expression; it includes an optional positional variable for counting/numbering the bindings. By default no ordering is implied or assumed by a <tt>for</tt> clause. A <tt>let</tt> clause binds a variable to the collection of elements computed by its associated expression.</p>
+<p>Following the initial <tt>for</tt> or <tt>let</tt> clause(s), a FLWOR expression may contain an arbitrary sequence of other clauses. The <tt>where</tt> clause in a FLWOR expression filters the preceding bindings via a boolean expression, much like a <tt>where</tt> clause does in a SQL query. The <tt>order by</tt> clause in a FLWOR expression induces an ordering on the data. The <tt>group by</tt> clause, discussed further below, forms groups based on its group by expressions, optionally naming the expressions’ values (which together form the grouping key for the expression). The <tt>with</tt> subclause of a <tt>group by</tt> clause specifies the variable(s) whose values should be grouped based on the grouping key(s); following the grouping clause, only the grouping key(s) and the variables named in the with subclause remain in scope, and the named grouping variables now contain lists formed from their input values. The <tt>limit</tt> clause caps the number of values returned, optionally starting its result count from a specified offset. (Web applications can use this feature for doing pagination.) The <tt>distinct</tt> clause is similar to the <tt>group-by</tt> clause, but it forms no groups; it serves only to eliminate duplicate values. As indicated by the grammar, the clauses in an AQL query can appear in any order. To interpret a query, one can think of data as flowing down through the query from the first clause to the <tt>return</tt> clause.</p>
+<p>The following example shows a FLWOR expression that selects and returns one user from the dataset FacebookUsers.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>for $user in dataset FacebookUsers
+where $user.id = 8
+return $user
+</pre></div></div>
+<p>The next example shows a FLWOR expression that joins two datasets, FacebookUsers and FacebookMessages, returning user/message pairs. The results contain one object per pair, with result objects containing the user’s name and an entire message.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>for $user in dataset FacebookUsers
+for $message in dataset FacebookMessages
+where $message.author-id = $user.id
+return
+ {
+ "uname": $user.name,
+ "message": $message.message
+ };
+</pre></div></div>
+<p>In the next example, a <tt>let</tt> clause is used to bind a variable to all of a user’s FacebookMessages. The query returns one object per user, with result objects containing the user’s name and the set of all messages by that user.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>for $user in dataset FacebookUsers
+let $messages :=
+ for $message in dataset FacebookMessages
+ where $message.author-id = $user.id
+ return $message.message
+return
+ {
+ "uname": $user.name,
+ "messages": $messages
+ };
+</pre></div></div>
+<p>The following example returns all TwitterUsers ordered by their followers count (most followers first) and language. When ordering <tt>null</tt> is treated as being smaller than any other value if <tt>null</tt>s are encountered in the ordering key(s).</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre> for $user in dataset TwitterUsers
+ order by $user.followers_count desc, $user.lang asc
+ return $user
+</pre></div></div>
+<p>The next example illustrates the use of the <tt>group by</tt> clause in AQL. After the <tt>group by</tt> clause in the query, only variables that are either in the <tt>group by</tt> list or in the <tt>with</tt> list are in scope. The variables in the clause’s <tt>with</tt> list will each contain a collection of items following the <tt>group by</tt> clause; the collected items are the values that the source variable was bound to in the tuples that formed the group. For grouping <tt>null</tt> is handled as a single value.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre> for $x in dataset FacebookMessages
+ let $messages := $x.message
+ group by $loc := $x.sender-location with $messages
+ return
+ {
+ "location" : $loc,
+ "message" : $messages
+ }
+</pre></div></div>
+<p>The use of the <tt>limit</tt> clause is illustrated in the next example.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre> for $user in dataset TwitterUsers
+ order by $user.followers_count desc
+ limit 2
+ return $user
+</pre></div></div>
+<p>The final example shows how AQL’s <tt>distinct by</tt> clause works. Each variable in scope before the distinct clause is also in scope after the <tt>distinct by</tt> clause. This clause works similarly to <tt>group by</tt>, but for each variable that contains more than one value after the <tt>distinct by</tt> clause, one value is picked nondeterministically. (If the variable is in the <tt>distinct by</tt> list, then its value will be deterministic.) Nulls are treated as a single value when they occur in a grouping field.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre> for $x in dataset FacebookMessages
+ distinct by $x.sender-location
+ return
+ {
+ "location" : $x.sender-location,
+ "message" : $x.message
+ }
+</pre></div></div>
+<p>In order to allow SQL fans to write queries in their favored ways, AQL provides synonyms: <i>from</i> for <i>for</i>, <i>select</i> for <i>return</i>, <i>with</i> for <i>let</i>, and <i>keeping</i> for <i>with</i> in the group by clause. The following query is such an example.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre> from $x in dataset FacebookMessages
+ with $messages := $x.message
+ group by $loc := $x.sender-location keeping $messages
+ select
+ {
+ "location" : $loc,
+ "message" : $messages
+ }
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Conditional_Expression"></a>Conditional Expression</h3>
+
+<div class="source">
+<div class="source">
+<pre>IfThenElse ::= "if" "(" Expression ")" "then" Expression "else" Expression
+</pre></div></div>
+<p>A conditional expression is useful for choosing between two alternative values based on a boolean condition. If its first (<tt>if</tt>) expression is true, its second (<tt>then</tt>) expression’s value is returned, and otherwise its third (<tt>else</tt>) expression is returned.</p>
+<p>The following example illustrates the form of a conditional expression.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>if (2 < 3) then "yes" else "no"
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Quantified_Expressions"></a>Quantified Expressions</h3>
+
+<div class="source">
+<div class="source">
+<pre>QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression
+ ( "," Variable "in" Expression )* "satisfies" Expression
+</pre></div></div>
+<p>Quantified expressions are used for expressing existential or universal predicates involving the elements of a collection.</p>
+<p>The following pair of examples illustrate the use of a quantified expression to test that every (or some) element in the set [1, 2, 3] of integers is less than three. The first example yields <tt>false</tt> and second example yields <tt>true</tt>.</p>
+<p>It is useful to note that if the set were instead the empty set, the first expression would yield <tt>true</tt> (“every” value in an empty set satisfies the condition) while the second expression would yield <tt>false</tt> (since there isn’t “some” value, as there are no values in the set, that satisfies the condition).</p>
+<div class="section">
+<div class="section">
+<h5><a name="Examples"></a>Examples</h5>
+
+<div class="source">
+<div class="source">
+<pre>every $x in [ 1, 2, 3 ] satisfies $x < 3
+some $x in [ 1, 2, 3 ] satisfies $x < 3
+</pre></div></div></div></div></div></div>
+<div class="section">
+<h2><a name="a3._Statements_Back_to_TOC"></a><a name="Statements" id="Statements">3. Statements</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+
+<div class="source">
+<div class="source">
+<pre>Statement ::= ( SingleStatement ( ";" )? )* <EOF>
+SingleStatement ::= DataverseDeclaration
+ | FunctionDeclaration
+ | CreateStatement
+ | DropStatement
+ | LoadStatement
+ | SetStatement
+ | InsertStatement
+ | DeleteStatement
+ | UpsertStatement
+ | Query
+</pre></div></div>
+<p>In addition to expresssions for queries, AQL supports a variety of statements for data definition and manipulation purposes as well as controlling the context to be used in evaluating AQL expressions. AQL supports object-level ACID transactions that begin and terminate implicitly for each object inserted, deleted, upserted, or searched while a given AQL statement is being executed.</p>
+<p>This section details the statements supported in the AQL language.</p>
+<div class="section">
+<h3><a name="Declarations"></a>Declarations</h3>
+
+<div class="source">
+<div class="source">
+<pre>DataverseDeclaration ::= "use" "dataverse" Identifier
+</pre></div></div>
+<p>The world of data in an AsterixDB cluster is organized into data namespaces called dataverses. To set the default dataverse for a series of statements, the use dataverse statement is provided.</p>
+<p>As an example, the following statement sets the default dataverse to be TinySocial.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>use dataverse TinySocial;
+</pre></div></div>
+<p>The set statement in AQL is used to control aspects of the expression evalation context for queries.</p>
+
+<div class="source">
+<div class="source">
+<pre>SetStatement ::= "set" Identifier StringLiteral
+</pre></div></div>
+<p>As an example, the following set statements request that Jaccard similarity with a similarity threshold 0.6 be used for set similarity matching when the ~= operator is used in a query expression.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>set simfunction "jaccard";
+set simthreshold "0.6f";
+</pre></div></div>
+<p>When writing a complex AQL query, it can sometimes be helpful to define one or more auxilliary functions that each address a sub-piece of the overall query. The declare function statement supports the creation of such helper functions.</p>
+
+<div class="source">
+<div class="source">
+<pre>FunctionDeclaration ::= "declare" "function" Identifier ParameterList "{" Expression "}"
+ParameterList ::= "(" ( <VARIABLE> ( "," <VARIABLE> )* )? ")"
+</pre></div></div>
+<p>The following is a very simple example of a temporary AQL function definition.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>declare function add($a, $b) {
+ $a + $b
+};
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Lifecycle_Management_Statements"></a>Lifecycle Management Statements</h3>
+
+<div class="source">
+<div class="source">
+<pre>CreateStatement ::= "create" ( DataverseSpecification
+ | TypeSpecification
+ | DatasetSpecification
+ | IndexSpecification
+ | FunctionSpecification )
+
+QualifiedName ::= Identifier ( "." Identifier )?
+DoubleQualifiedName ::= Identifier "." Identifier ( "." Identifier )?
+</pre></div></div>
+<p>The create statement in AQL is used for creating persistent artifacts in the context of dataverses. It can be used to create new dataverses, datatypes, datasets, indexes, and user-defined AQL functions.</p>
+<div class="section">
+<h4><a name="Dataverses"></a>Dataverses</h4>
+
+<div class="source">
+<div class="source">
+<pre>DataverseSpecification ::= "dataverse" Identifier IfNotExists ( "with format" StringLiteral )?
+</pre></div></div>
+<p>The create dataverse statement is used to create new dataverses. To ease the authoring of reusable AQL scripts, its optional IfNotExists clause allows creation to be requested either unconditionally or only if the the dataverse does not already exist. If this clause is absent, an error will be returned if the specified dataverse already exists. The <tt>with format</tt> clause is a placeholder for future functionality that can safely be ignored.</p>
+<p>The following example creates a dataverse named TinySocial.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create dataverse TinySocial;
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Types"></a>Types</h4>
+
+<div class="source">
+<div class="source">
+<pre>TypeSpecification ::= "type" FunctionOrTypeName IfNotExists "as" TypeExpr
+FunctionOrTypeName ::= QualifiedName
+IfNotExists ::= ( "if not exists" )?
+TypeExpr ::= ObjectTypeDef | TypeReference | OrderedListTypeDef | UnorderedListTypeDef
+ObjectTypeDef ::= ( "closed" | "open" )? "{" ( ObjectField ( "," ObjectField )* )? "}"
+ObjectField ::= Identifier ":" ( TypeExpr ) ( "?" )?
+NestedField ::= Identifier ( "." Identifier )*
+IndexField ::= NestedField ( ":" TypeReference )?
+TypeReference ::= Identifier
+OrderedListTypeDef ::= "[" ( TypeExpr ) "]"
+UnorderedListTypeDef ::= "{{" ( TypeExpr ) "}}"
+</pre></div></div>
+<p>The create type statement is used to create a new named ADM datatype. This type can then be used to create datasets or utilized when defining one or more other ADM datatypes. Much more information about the Asterix Data Model (ADM) is available in the <a href="datamodel.html">data model reference guide</a> to ADM. A new type can be a object type, a renaming of another type, an ordered list type, or an unordered list type. A object type can be defined as being either open or closed. Instances of a closed object type are not permitted to contain fields other than those specified in the create type statement. Instances of an open object type may carry additional fields, and open is the default for a new type (if neither option is specified).</p>
+<p>The following example creates a new ADM object type called FacebookUser type. Since it is closed, its instances will contain only what is specified in the type definition. The first four fields are traditional typed name/value pairs. The friend-ids field is an unordered list of 32-bit integers. The employment field is an ordered list of instances of another named object type, EmploymentType.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create type FacebookUserType as closed {
+ "id" : int32,
+ "alias" : string,
+ "name" : string,
+ "user-since" : datetime,
+ "friend-ids" : {{ int32 }},
+ "employment" : [ EmploymentType ]
+}
+</pre></div></div>
+<p>The next example creates a new ADM object type called FbUserType. Note that the type of the id field is UUID. You need to use this field type if you want to have this field be an autogenerated-PK field. Refer to the Datasets section later for more details.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create type FbUserType as closed {
+ "id" : uuid,
+ "alias" : string,
+ "name" : string
+}
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Datasets"></a>Datasets</h4>
+
+<div class="source">
+<div class="source">
+<pre>DatasetSpecification ::= "internal"? "dataset" QualifiedName "(" QualifiedName ")" IfNotExists
+ PrimaryKey ( "on" Identifier )? ( "hints" Properties )?
+ ( "using" "compaction" "policy" CompactionPolicy ( Configuration )? )?
+ ( "with filter on" Identifier )?
+ | "external" "dataset" QualifiedName "(" QualifiedName ")" IfNotExists
+ "using" AdapterName Configuration ( "hints" Properties )?
+ ( "using" "compaction" "policy" CompactionPolicy ( Configuration )? )?
+AdapterName ::= Identifier
+Configuration ::= "(" ( KeyValuePair ( "," KeyValuePair )* )? ")"
+KeyValuePair ::= "(" StringLiteral "=" StringLiteral ")"
+Properties ::= ( "(" Property ( "," Property )* ")" )?
+Property ::= Identifier "=" ( StringLiteral | IntegerLiteral )
+FunctionSignature ::= FunctionOrTypeName "@" IntegerLiteral
+PrimaryKey ::= "primary" "key" NestedField ( "," NestedField )* ( "autogenerated ")?
+CompactionPolicy ::= Identifier
+PrimaryKey ::= "primary" "key" Identifier ( "," Identifier )* ( "autogenerated ")?
+</pre></div></div>
+<p>The create dataset statement is used to create a new dataset. Datasets are named, unordered collections of ADM object instances; they are where data lives persistently and are the targets for queries in AsterixDB. Datasets are typed, and AsterixDB will ensure that their contents conform to their type definitions. An Internal dataset (the default) is a dataset that is stored in and managed by AsterixDB. It must have a specified unique primary key that can be used to partition data across nodes of an AsterixDB cluster. The primary key is also used in secondary indexes to uniquely identify the indexed primary data objects. Random primary key (UUID) values can be auto-generated by declaring the field to be UUID and putting “autogenerated” after the “primary key” identifier. In this case, values for the auto-generated PK field should not be provided by the user since it will be auto-generated by AsterixDB. Optionally, a filter can be created on a field to further optimize range queries with predicates on the filter’s field. (Refer to <a href="filters.html">Filter-Based LSM Index Acceleration</a> for more information about filters.)</p>
+<p>An External dataset is stored outside of AsterixDB (currently datasets in HDFS or on the local filesystem(s) of the cluster’s nodes are supported). External dataset support allows AQL queries to treat external data as though it were stored in AsterixDB, making it possible to query “legacy” file data (e.g., Hive data) without having to physically import it into AsterixDB. For an external dataset, an appropriate adapter must be selected to handle the nature of the desired external data. (See the <a href="externaldata.html">guide to external data</a> for more information on the available adapters.)</p>
+<p>When creating a dataset, it is possible to choose a merge policy that controls which of the underlaying LSM storage components to be merged. Currently, AsterixDB provides four different merge policies that can be configured per dataset: no-merge, constant, prefix, and correlated-prefix. The no-merge policy simply never merges disk components. While the constant policy merges disk components when the number of components reaches some constant number k, which can be configured by the user. The prefix policy relies on component sizes and the number of components to decide which components to merge. Specifically, it works by first trying to identify the smallest ordered (oldest to newest) sequence of components such that the sequence does not contain a single component that exceeds some threshold size M and that either the sum of the component’s sizes exceeds M or the number of components in the sequence exceeds another threshold C. If such a sequence of components exists, then each of the components in the sequence are merged together to form a single component. Finally, the correlated-prefix is similar to the prefix policy but it delegates the decision of merging the disk components of all the indexes in a dataset to the primary index. When the policy decides that the primary index needs to be merged (using the same decision criteria as for the prefix policy), then it will issue successive merge requests on behalf of all other indexes associated with the same dataset. The default policy for AsterixDB is the prefix policy except when there is a filter on a dataset, where the preferred policy for filters is the correlated-prefix.</p>
+<p>The following example creates an internal dataset for storing FacefookUserType objects. It specifies that their id field is their primary key.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create internal dataset FacebookUsers(FacebookUserType) primary key id;
+</pre></div></div>
+<p>The following example creates an internal dataset for storing FbUserType objects. It specifies that their id field is their primary key. It also specifies that the id field is an auto-generated field, meaning that a randomly generated UUID value will be assigned to each object by the system. (A user should therefore not proivde a value for this field.) Note that the id field should be UUID.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create internal dataset FbMsgs(FbUserType) primary key id autogenerated;
+</pre></div></div>
+<p>The next example creates an external dataset for storing LineitemType objects. The choice of the <tt>hdfs</tt> adapter means that its data will reside in HDFS. The create statement provides parameters used by the hdfs adapter: the URL and path needed to locate the data in HDFS and a description of the data format.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create external dataset Lineitem('LineitemType) using hdfs (
+ ("hdfs"="hdfs://HOST:PORT"),
+ ("path"="HDFS_PATH"),
+ ("input-format"="text-input-format"),
+ ("format"="delimited-text"),
+ ("delimiter"="|"));
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Indices"></a>Indices</h4>
+
+<div class="source">
+<div class="source">
+<pre>IndexSpecification ::= "index" Identifier IfNotExists "on" QualifiedName
+ "(" ( IndexField ) ( "," IndexField )* ")" ( "type" IndexType )? ( "enforced" )?
+IndexType ::= "btree"
+ | "rtree"
+ | "keyword"
+ | "ngram" "(" IntegerLiteral ")"
+ | "fulltext"
+</pre></div></div>
+<p>The create index statement creates a secondary index on one or more fields of a specified dataset. Supported index types include <tt>btree</tt> for totally ordered datatypes, <tt>rtree</tt> for spatial data, and <tt>keyword</tt>, <tt>ngram</tt>, and <tt>fulltext</tt> for textual (string) data. An index can be created on a nested field (or fields) by providing a valid path expression as an index field identifier. An index field is not required to be part of the datatype associated with a dataset if that datatype is declared as open and the field’s type is provided along with its type and the <tt>enforced</tt> keyword is specified in the end of index definition. <tt>Enforcing</tt> an open field will introduce a check that will make sure that the actual type of an indexed field (if the field exists in the object) always matches this specified (open) field type.</p>
+<p>The following example creates a btree index called fbAuthorIdx on the author-id field of the FacebookMessages dataset. This index can be useful for accelerating exact-match queries, range search queries, and joins involving the author-id field.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index fbAuthorIdx on FacebookMessages(author-id) type btree;
+</pre></div></div>
+<p>The following example creates an open btree index called fbSendTimeIdx on the open send-time field of the FacebookMessages dataset having datetime type. This index can be useful for accelerating exact-match queries, range search queries, and joins involving the send-time field.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index fbSendTimeIdx on FacebookMessages(send-time:datetime) type btree enforced;
+</pre></div></div>
+<p>The following example creates a btree index called twUserScrNameIdx on the screen-name field, which is a nested field of the user field in the TweetMessages dataset. This index can be useful for accelerating exact-match queries, range search queries, and joins involving the screen-name field.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index twUserScrNameIdx on TweetMessages(user.screen-name) type btree;
+</pre></div></div>
+<p>The following example creates an rtree index called fbSenderLocIdx on the sender-location field of the FacebookMessages dataset. This index can be useful for accelerating queries that use the <a href="functions.html#spatial-intersect"><tt>spatial-intersect</tt> function</a> in a predicate involving the sender-location field.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index fbSenderLocIndex on FacebookMessages(sender-location) type rtree;
+</pre></div></div>
+<p>The following example creates a 3-gram index called fbUserIdx on the name field of the FacebookUsers dataset. This index can be used to accelerate some similarity or substring maching queries on the name field. For details refer to the <a href="similarity.html#NGram_Index">document on similarity queries</a>.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index fbUserIdx on FacebookUsers(name) type ngram(3);
+</pre></div></div>
+<p>The following example creates a keyword index called fbMessageIdx on the message field of the FacebookMessages dataset. This keyword index can be used to optimize queries with token-based similarity predicates on the message field. For details refer to the <a href="similarity.html#Keyword_Index">document on similarity queries</a>.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index fbMessageIdx on FacebookMessages(message) type keyword;
+</pre></div></div>
+<p>The following example creates a full-text index called fbMessageIdx on the message field of the FacebookMessages dataset. This full-text index can be used to optimize queries with full-text search predicates on the message field. For details refer to the <a href="fulltext.html#toc">document on full-text queries</a>.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create index fbMessageIdx on FacebookMessages(message) type fulltext;
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Functions"></a>Functions</h4>
+<p>The create function statement creates a named function that can then be used and reused in AQL queries. The body of a function can be any AQL expression involving the function’s parameters.</p>
+
+<div class="source">
+<div class="source">
+<pre>FunctionSpecification ::= "function" FunctionOrTypeName IfNotExists ParameterList "{" Expression "}"
+</pre></div></div>
+<p>The following is a very simple example of a create function statement. It differs from the declare function example shown previously in that it results in a function that is persistently registered by name in the specified dataverse.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>create function add($a, $b) {
+ $a + $b
+};
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Removal"></a>Removal</h4>
+
+<div class="source">
+<div class="source">
+<pre>DropStatement ::= "drop" ( "dataverse" Identifier IfExists
+ | "type" FunctionOrTypeName IfExists
+ | "dataset" QualifiedName IfExists
+ | "index" DoubleQualifiedName IfExists
+ | "function" FunctionSignature IfExists )
+IfExists ::= ( "if" "exists" )?
+</pre></div></div>
+<p>The drop statement in AQL is the inverse of the create statement. It can be used to drop dataverses, datatypes, datasets, indexes, and functions.</p>
+<p>The following examples illustrate uses of the drop statement.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>drop dataset FacebookUsers if exists;
+
+drop index FacebookUsers.fbSenderLocIndex;
+
+drop type FacebookUserType;
+
+drop dataverse TinySocial;
+
+drop function add;
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="ImportExport_Statements"></a>Import/Export Statements</h3>
+
+<div class="source">
+<div class="source">
+<pre>LoadStatement ::= "load" "dataset" QualifiedName "using" AdapterName Configuration ( "pre-sorted" )?
+</pre></div></div>
+<p>The load statement is used to initially populate a dataset via bulk loading of data from an external file. An appropriate adapter must be selected to handle the nature of the desired external data. The load statement accepts the same adapters and the same parameters as external datasets. (See the <a href="externaldata.html">guide to external data</a> for more information on the available adapters.) If a dataset has an auto-generated primary key field, a file to be imported should not include that field in it.</p>
+<p>The following example shows how to bulk load the FacebookUsers dataset from an external file containing data that has been prepared in ADM format.</p>
+<div class="section">
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>load dataset FacebookUsers using localfs
+(("path"="localhost:///Users/zuck/AsterixDB/load/fbu.adm"),("format"="adm"));
+</pre></div></div></div></div></div>
+<div class="section">
+<h3><a name="Modification_Statements"></a>Modification Statements</h3>
+<div class="section">
+<h4><a name="Insert"></a>Insert</h4>
+
+<div class="source">
+<div class="source">
+<pre>InsertStatement ::= "insert" "into" "dataset" QualifiedName ( "as" Variable )? Query ( "returning" Query )?
+</pre></div></div>
+<p>The AQL insert statement is used to insert data into a dataset. The data to be inserted comes from an AQL query expression. The expression can be as simple as a constant expression, or in general it can be any legal AQL query. Inserts in AsterixDB are processed transactionally, with the scope of each insert transaction being the insertion of a single object plus its affiliated secondary index entries (if any). If the query part of an insert returns a single object, then the insert statement itself will be a single, atomic transaction. If the query part returns multiple objects, then each object inserted will be handled independently as a tranaction. If a dataset has an auto-generated primary key field, an insert statement should not include a value for that field in it. (The system will automatically extend the provided object with this additional field and a corresponding value.). The optional “as Variable” provides a variable binding for the inserted objects, which can be used in the “returning” clause. The optional “returning Query” allows users to run simple queries/functions on the objects returned by the insert. This query cannot refer to any datasets.</p>
+<p>The following example illustrates a query-based insertion.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>insert into dataset UsersCopy as $inserted (for $user in dataset FacebookUsers return $user ) returning $inserted.screen-name
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Delete"></a>Delete</h4>
+
+<div class="source">
+<div class="source">
+<pre>DeleteStatement ::= "delete" Variable "from" "dataset" QualifiedName ( "where" Expression )?
+</pre></div></div>
+<p>The AQL delete statement is used to delete data from a target dataset. The data to be deleted is identified by a boolean expression involving the variable bound to the target dataset in the delete statement. Deletes in AsterixDB are processed transactionally, with the scope of each delete transaction being the deletion of a single object plus its affiliated secondary index entries (if any). If the boolean expression for a delete identifies a single object, then the delete statement itself will be a single, atomic transaction. If the expression identifies multiple objects, then each object deleted will be handled independently as a transaction.</p>
+<p>The following example illustrates a single-object deletion.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>delete $user from dataset FacebookUsers where $user.id = 8;
+</pre></div></div></div></div>
+<div class="section">
+<h4><a name="Upsert"></a>Upsert</h4>
+
+<div class="source">
+<div class="source">
+<pre>UpsertStatement ::= "upsert" "into" "dataset" QualifiedName Query
+</pre></div></div>
+<p>The AQL upsert statement is used to couple delete (if found) with insert data into a dataset. The data to be upserted comes from an AQL query expression. The expression can be as simple as a constant expression, or in general it can be any legal AQL query. Upserts in AsterixDB are processed transactionally, with the scope of each upsert transaction being the upsertion (deletion if found + insertion) of a single object plus its affiliated secondary index entries (if any). If the query part of an upsert returns a single object, then the upsert statement itself will be a single, atomic transaction. If the query part returns multiple objects, then each object upserted will be handled independently as a tranaction.</p>
+<p>The following example illustrates a query-based upsertion.</p>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>upsert into dataset Users (for $user in dataset FacebookUsers return $user)
+</pre></div></div>
+<p>We close this guide to AQL with one final example of a query expression.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+
+<div class="source">
+<div class="source">
+<pre>for $praise in {{ "great", "brilliant", "awesome" }}
+return
+ string-concat(["AsterixDB is ", $praise])
+</pre></div></div></div></div></div></div>
+ </div>
+ </div>
+ </div>
+
+ <hr/>
+
+ <footer>
+ <div class="container-fluid">
+ <div class="row span12">Copyright © 2017
+ <a href="https://www.apache.org/">The Apache Software Foundation</a>.
+ All Rights Reserved.
+
+ </div>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<div class="row-fluid">Apache AsterixDB, AsterixDB, Apache, the Apache
+ feather logo, and the Apache AsterixDB project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.</div>
+
+
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/docs/0.9.0/aql/primer.html b/docs/0.9.0/aql/primer.html
new file mode 100644
index 0000000..f845045
--- /dev/null
+++ b/docs/0.9.0/aql/primer.html
@@ -0,0 +1,983 @@
+<!DOCTYPE html>
+<!--
+ | Generated by Apache Maven Doxia at 2017-01-24
+ | Rendered using Apache Maven Fluido Skin 1.3.0
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="Date-Revision-yyyymmdd" content="20170124" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>AsterixDB – AsterixDB 101: An ADM and AQL Primer</title>
+ <link rel="stylesheet" href="../css/apache-maven-fluido-1.3.0.min.css" />
+ <link rel="stylesheet" href="../css/site.css" />
+ <link rel="stylesheet" href="../css/print.css" media="print" />
+
+
+ <script type="text/javascript" src="../js/apache-maven-fluido-1.3.0.min.js"></script>
+
+
+
+<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-41536543-1', 'uci.edu');
+ ga('send', 'pageview');</script>
+
+ </head>
+ <body class="topBarDisabled">
+
+
+
+
+ <div class="container-fluid">
+ <div id="banner">
+ <div class="pull-left">
+ <a href=".././" id="bannerLeft">
+ <img src="../images/asterixlogo.png" alt="AsterixDB"/>
+ </a>
+ </div>
+ <div class="pull-right"> </div>
+ <div class="clear"><hr/></div>
+ </div>
+
+ <div id="breadcrumbs">
+ <ul class="breadcrumb">
+
+
+ <li id="publishDate">Last Published: 2017-01-24</li>
+
+
+
+ <li id="projectVersion" class="pull-right">Version: 0.9.0</li>
+
+ <li class="divider pull-right">|</li>
+
+ <li class="pull-right"> <a href="../index.html" title="Documentation Home">
+ Documentation Home</a>
+ </li>
+
+ </ul>
+ </div>
+
+
+ <div class="row-fluid">
+ <div id="leftColumn" class="span3">
+ <div class="well sidebar-nav">
+
+
+ <ul class="nav nav-list">
+ <li class="nav-header">Get Started - Installation</li>
+
+ <li>
+
+ <a href="../ncservice.html" title="Option 1: using NCService">
+ <i class="none"></i>
+ Option 1: using NCService</a>
+ </li>
+
+ <li>
+
+ <a href="../install.html" title="Option 2: using Managix">
+ <i class="none"></i>
+ Option 2: using Managix</a>
+ </li>
+
+ <li>
+
+ <a href="../yarn.html" title="Option 3: using YARN">
+ <i class="none"></i>
+ Option 3: using YARN</a>
+ </li>
+ <li class="nav-header">AsterixDB Primer</li>
+
+ <li>
+
+ <a href="../sqlpp/primer-sqlpp.html" title="Option 1: using SQL++">
+ <i class="none"></i>
+ Option 1: using SQL++</a>
+ </li>
+
+ <li class="active">
+
+ <a href="#"><i class="none"></i>Option 2: using AQL</a>
+ </li>
+ <li class="nav-header">Data Model</li>
+
+ <li>
+
+ <a href="../datamodel.html" title="The Asterix Data Model">
+ <i class="none"></i>
+ The Asterix Data Model</a>
+ </li>
+ <li class="nav-header">Queries - SQL++</li>
+
+ <li>
+
+ <a href="../sqlpp/manual.html" title="The SQL++ Query Language">
+ <i class="none"></i>
+ The SQL++ Query Language</a>
+ </li>
+
+ <li>
+
+ <a href="../sqlpp/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Queries - AQL</li>
+
+ <li>
+
+ <a href="../aql/manual.html" title="The Asterix Query Language (AQL)">
+ <i class="none"></i>
+ The Asterix Query Language (AQL)</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Advanced Features</li>
+
+ <li>
+
+ <a href="../aql/similarity.html" title="Support of Similarity Queries">
+ <i class="none"></i>
+ Support of Similarity Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/fulltext.html" title="Support of Full-text Queries">
+ <i class="none"></i>
+ Support of Full-text Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/externaldata.html" title="Accessing External Data">
+ <i class="none"></i>
+ Accessing External Data</a>
+ </li>
+
+ <li>
+
+ <a href="../feeds/tutorial.html" title="Support for Data Ingestion">
+ <i class="none"></i>
+ Support for Data Ingestion</a>
+ </li>
+
+ <li>
+
+ <a href="../udf.html" title="User Defined Functions">
+ <i class="none"></i>
+ User Defined Functions</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/filters.html" title="Filter-Based LSM Index Acceleration">
+ <i class="none"></i>
+ Filter-Based LSM Index Acceleration</a>
+ </li>
+ <li class="nav-header">API/SDK</li>
+
+ <li>
+
+ <a href="../api.html" title="HTTP API">
+ <i class="none"></i>
+ HTTP API</a>
+ </li>
+ </ul>
+
+
+
+ <hr class="divider" />
+
+ <div id="poweredBy">
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <a href=".././" title="AsterixDB" class="builtBy">
+ <img class="builtBy" alt="AsterixDB" src="../images/asterixlogo.png" />
+ </a>
+ </div>
+ </div>
+ </div>
+
+
+ <div id="bodyColumn" class="span9" >
+
+ <!-- ! 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.
+ ! --><h1>AsterixDB 101: An ADM and AQL Primer</h1>
+<div class="section">
+<h2><a name="Welcome_to_AsterixDB"></a>Welcome to AsterixDB!</h2>
+<p>This document introduces the main features of AsterixDB’s data model (ADM) and query language (AQL) by example. The example is a simple scenario involving (synthetic) sample data modeled after data from the social domain. This document describes a set of sample ADM datasets, together with a set of illustrative AQL queries, to introduce you to the “AsterixDB user experience”. The complete set of steps required to create and load a handful of sample datasets, along with runnable queries and the expected results for each query, are included.</p>
+<p>This document assumes that you are at least vaguely familiar with AsterixDB and why you might want to use it. Most importantly, it assumes you already have a running instance of AsterixDB and that you know how to query it using AsterixDB’s basic web interface. For more information on these topics, you should go through the steps in <a href="../install.html">Installing Asterix Using Managix</a> before reading this document and make sure that you have a running AsterixDB instance ready to go. To get your feet wet, you should probably start with a simple local installation of AsterixDB on your favorite machine, accepting all of the default settings that Managix offers. Later you can graduate to trying AsterixDB on a cluster, its real intended home (since it targets Big Data). (Note: With the exception of specifying the correct locations where you put the source data for this example, there should no changes needed in your ADM or AQL statements to run the examples locally and/or to run them on a cluster when you are ready to take that step.)</p>
+<p>As you read through this document, you should try each step for yourself on your own AsterixDB instance. Once you have reached the end, you will be fully armed and dangerous, with all the basic AsterixDB knowledge that you’ll need to start down the path of modeling, storing, and querying your own semistructured data.</p></div>
+<div class="section">
+<h2><a name="ADM:_Modeling_Semistructed_Data_in_AsterixDB"></a>ADM: Modeling Semistructed Data in AsterixDB</h2>
+<p>In this section you will learn all about modeling Big Data using ADM, the data model of the AsterixDB BDMS.</p>
+<div class="section">
+<h3><a name="Dataverses_Datatypes_and_Datasets"></a>Dataverses, Datatypes, and Datasets</h3>
+<p>The top-level organizing concept in the AsterixDB world is the <i>dataverse</i>. A dataverse—short for “data universe”—is a place (similar to a database in a relational DBMS) in which to create and manage the types, datasets, functions, and other artifacts for a given AsterixDB application. When you start using an AsterixDB instance for the first time, it starts out “empty”; it contains no data other than the AsterixDB system catalogs (which live in a special dataverse called the Metadata dataverse). To store your data in AsterixDB, you will first create a dataverse and then you use it for the <i>datatypes</i> and <i>datasets</i> for managing your own data. A datatype tells AsterixDB what you know (or more accurately, what you want it to know) a priori about one of the kinds of data instances that you want AsterixDB to hold for you. A dataset is a collection of data instances of a datatype, and AsterixDB makes sure that the data instances that you put in it conform to its specified type. Since AsterixDB targets semistructured data, you can use <i>open</i> datatypes and tell it as little or as much as you wish about your data up front; the more you tell it up front, the less information it will have to store repeatedly in the individual data instances that you give it. Instances of open datatypes are permitted to have additional content, beyond what the datatype says, as long as they at least contain the information prescribed by the datatype definition. Open typing allows data to vary from one instance to another and it leaves wiggle room for application evolution in terms of what might need to be stored in the future. If you want to restrict data instances in a dataset to have only what the datatype says, and nothing extra, you can define a <i>closed</i> datatype for that dataset and AsterixDB will keep users from storing objects that have extra data in them. Datatypes are open by default unless you tell AsterixDB otherwise. Let’s put these concepts to work</p>
+<p>Our little sample scenario involves information about users of two hypothetical social networks, Gleambook and Chirp, and their messages. We’ll start by defining a dataverse called “TinySocial” to hold our datatypes and datasets. The AsterixDB data model (ADM) is essentially a superset of JSON—it’s what you get by extending JSON with more data types and additional data modeling constructs borrowed from object databases. The following shows how we can create the TinySocial dataverse plus a set of ADM types for modeling Chirp users, their Chirps, Gleambook users, their users’ employment information, and their messages. (Note: Keep in mind that this is just a tiny and somewhat silly example intended for illustrating some of the key features of AsterixDB. :-))</p>
+
+<div class="source">
+<div class="source">
+<pre> drop dataverse TinySocial if exists;
+ create dataverse TinySocial;
+ use dataverse TinySocial;
+
+ create type ChirpUserType as {
+ screenName: string,
+ lang: string,
+ friendsCount: int,
+ statusesCount: int,
+ name: string,
+ followersCount: int
+ };
+
+ create type ChirpMessageType as closed {
+ chirpId: string,
+ user: ChirpUserType,
+ senderLocation: point?,
+ sendTime: datetime,
+ referredTopics: {{ string }},
+ messageText: string
+ };
+
+ create type EmploymentType as {
+ organizationName: string,
+ startDate: date,
+ endDate: date?
+ };
+
+ create type GleambookUserType as {
+ id: int,
+ alias: string,
+ name: string,
+ userSince: datetime,
+ friendIds: {{ int }},
+ employment: [EmploymentType]
+ };
+
+ create type GleambookMessageType as {
+ messageId: int,
+ authorId: int,
+ inResponseTo: int?,
+ senderLocation: point?,
+ message: string
+ };
+</pre></div></div>
+<p>The first three lines above tell AsterixDB to drop the old TinySocial dataverse, if one already exists, and then to create a brand new one and make it the focus of the statements that follow. The first <i>create type</i> statement creates a datatype for holding information about Chirp users. It is a object type with a mix of integer and string data, very much like a (flat) relational tuple. The indicated fields are all mandatory, but because the type is open, additional fields are welcome. The second statement creates a datatype for Chirp messages; this shows how to specify a closed type. Interestingly (based on one of Chirp’s APIs), each Chirp message actually embeds an instance of the sending user’s information (current as of when the message was sent), so this is an example of a nested object in ADM. Chirp messages can optionally contain the sender’s location, which is modeled via the senderLocation field of spatial type <i>point</i>; the question mark following the field type indicates its optionality. An optional field is like a nullable field in SQL—it may be present or missing, but when it’s present, its value’s data type will conform to the datatype’s specification. The sendTime field illustrates the use of a temporal primitive type, <i>datetime</i>. Lastly, the referredTopics field illustrates another way that ADM is richer than the relational model; this field holds a bag (<i>a.k.a.</i> an unordered list) of strings. Since the overall datatype definition for Chirp messages says “closed”, the fields that it lists are the only fields that instances of this type will be allowed to contain. The next two <i>create type</i> statements create a object type for holding information about one component of the employment history of a Gleambook user and then a object type for holding the user information itself. The Gleambook user type highlights a few additional ADM data model features. Its friendIds field is a bag of integers, presumably the Gleambook user ids for this user’s friends, and its employment field is an ordered list of employment objects. The final <i>create type</i> statement defines a type for handling the content of a Gleambook message in our hypothetical social data storage scenario.</p>
+<p>Before going on, we need to once again emphasize the idea that AsterixDB is aimed at storing and querying not just Big Data, but Big <i>Semistructured</i> Data. This means that most of the fields listed in the <i>create type</i> statements above could have been omitted without changing anything other than the resulting size of stored data instances on disk. AsterixDB stores its information about the fields defined a priori as separate metadata, whereas the information about other fields that are “just there” in instances of open datatypes is stored with each instance—making for more bits on disk and longer times for operations affected by data size (e.g., dataset scans). The only fields that <i>must</i> be specified a priori are the primary key fields of each dataset.</p></div>
+<div class="section">
+<h3><a name="Creating_Datasets_and_Indexes"></a>Creating Datasets and Indexes</h3>
+<p>Now that we have defined our datatypes, we can move on and create datasets to store the actual data. (If we wanted to, we could even have several named datasets based on any one of these datatypes.) We can do this as follows, utilizing the DDL capabilities of AsterixDB.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ create dataset GleambookUsers(GleambookUserType)
+ primary key id;
+
+ create dataset GleambookMessages(GleambookMessageType)
+ primary key messageId;
+
+ create dataset ChirpUsers(ChirpUserType)
+ primary key screenName;
+
+ create dataset ChirpMessages(ChirpMessageType)
+ primary key chirpId
+ hints(cardinality=100);
+
+ create index gbUserSinceIdx on GleambookUsers(userSince);
+ create index gbAuthorIdx on GleambookMessages(authorId) type btree;
+ create index gbSenderLocIndex on GleambookMessages(senderLocation) type rtree;
+ create index gbMessageIdx on GleambookMessages(message) type keyword;
+
+ for $ds in dataset Metadata.Dataset return $ds;
+ for $ix in dataset Metadata.Index return $ix;
+</pre></div></div>
+<p>The DDL statements above create four datasets for holding our social data in the TinySocial dataverse: GleambookUsers, GleambookMessages, ChirpUsers, and ChirpMessages. The first <i>create dataset</i> statement creates the GleambookUsers data set. It specifies that this dataset will store data instances conforming to GleambookUserType and that it has a primary key which is the id field of each instance. The primary key information is used by AsterixDB to uniquely identify instances for the purpose of later lookup and for use in secondary indexes. Each AsterixDB dataset is stored (and indexed) in the form of a B+ tree on primary key; secondary indexes point to their indexed data by primary key. In AsterixDB clusters, the primary key is also used to hash-partition (<i>a.k.a.</i> shard) the dataset across the nodes of the cluster. The next three <i>create dataset</i> statements are similar. The last one illustrates an optional clause for providing useful hints to AsterixDB. In this case, the hint tells AsterixDB that the dataset definer is anticipating that the ChirpMessages dataset will contain roughly 100 objects; knowing this can help AsterixDB to more efficiently manage and query this dataset. (AsterixDB does not yet gather and maintain data statistics; it will currently, abitrarily, assume a cardinality of one million objects per dataset in the absence of such an optional definition-time hint.)</p>
+<p>The <i>create dataset</i> statements above are followed by four more DDL statements, each of which creates a secondary index on a field of one of the datasets. The first one indexes the GleambookUsers dataset on its userSince field. This index will be a B+ tree index; its type is unspecified and <i>btree</i> is the default type. The other three illustrate how you can explicitly specify the desired type of index. In addition to btree, <i>rtree</i> and inverted <i>keyword</i> indexes are supported by AsterixDB. Indexes can also have composite keys, and more advanced text indexing is available as well (ngram(k), where k is the desired gram length).</p></div>
+<div class="section">
+<h3><a name="Querying_the_Metadata_Dataverse"></a>Querying the Metadata Dataverse</h3>
+<p>The last two statements above show how you can use queries in AQL to examine the AsterixDB system catalogs and tell what artifacts you have created. Just as relational DBMSs use their own tables to store their catalogs, AsterixDB uses its own datasets to persist descriptions of its datasets, datatypes, indexes, and so on. Running the first of the two queries above will list all of your newly created datasets, and it will also show you a full list of all the metadata datasets. (You can then explore from there on your own if you are curious) These last two queries also illustrate one other factoid worth knowing: AsterixDB allows queries to span dataverses by allowing the optional use of fully-qualified dataset names (i.e., <i>dataversename.datasetname</i>) to reference datasets that live in a dataverse other than the one that was named in the most recently executed <i>use dataverse</i> directive.</p></div></div>
+<div class="section">
+<h2><a name="Loading_Data_Into_AsterixDB"></a>Loading Data Into AsterixDB</h2>
+<p>Okay, so far so good—AsterixDB is now ready for data, so let’s give it some data to store. Our next task will be to load some sample data into the four datasets that we just defined. Here we will load a tiny set of objects, defined in ADM format (a superset of JSON), into each dataset. In the boxes below you can see the actual data instances contained in each of the provided sample files. In order to load this data yourself, you should first store the four corresponding <tt>.adm</tt> files (whose URLs are indicated on top of each box below) into a filesystem directory accessible to your running AsterixDB instance. Take a few minutes to look carefully at each of the sample data sets. This will give you a better sense of the nature of the data that we are about to load and query. We should note that ADM format is a textual serialization of what AsterixDB will actually store; when persisted in AsterixDB, the data format will be binary and the data in the predefined fields of the data instances will be stored separately from their associated field name and type metadata.</p>
+<p><a href="../data/chu.adm">Chirp Users</a></p>
+
+<div class="source">
+<div class="source">
+<pre> {"screenName":"NathanGiesen@211","lang":"en","friendsCount":18,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416}
+ {"screenName":"ColineGeyer@63","lang":"en","friendsCount":121,"statusesCount":362,"name":"Coline Geyer","followersCount":17159}
+ {"screenName":"NilaMilliron_tw","lang":"en","friendsCount":445,"statusesCount":164,"name":"Nila Milliron","followersCount":22649}
+ {"screenName":"ChangEwing_573","lang":"en","friendsCount":182,"statusesCount":394,"name":"Chang Ewing","followersCount":32136}
+</pre></div></div>
+<p><a href="../data/chm.adm">Chirp Messages</a></p>
+
+<div class="source">
+<div class="source">
+<pre> {"chirpId":"1","user":{"screenName":"NathanGiesen@211","lang":"en","friendsCount":39339,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416},"senderLocation":point("47.44,80.65"),"sendTime":datetime("2008-04-26T10:10:00"),"referredTopics":{{"t-mobile","customization"}},"messageText":" love t-mobile its customization is good:)"}
+ {"chirpId":"2","user":{"screenName":"ColineGeyer@63","lang":"en","friendsCount":121,"statusesCount":362,"name":"Coline Geyer","followersCount":17159},"senderLocation":point("32.84,67.14"),"sendTime":datetime("2010-05-13T10:10:00"),"referredTopics":{{"verizon","shortcut-menu"}},"messageText":" like verizon its shortcut-menu is awesome:)"}
+ {"chirpId":"3","user":{"screenName":"NathanGiesen@211","lang":"en","friendsCount":39339,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416},"senderLocation":point("29.72,75.8"),"sendTime":datetime("2006-11-04T10:10:00"),"referredTopics":{{"motorola","speed"}},"messageText":" like motorola the speed is good:)"}
+ {"chirpId":"4","user":{"screenName":"NathanGiesen@211","lang":"en","friendsCount":39339,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416},"senderLocation":point("39.28,70.48"),"sendTime":datetime("2011-12-26T10:10:00"),"referredTopics":{{"sprint","voice-command"}},"messageText":" like sprint the voice-command is mind-blowing:)"}
+ {"chirpId":"5","user":{"screenName":"NathanGiesen@211","lang":"en","friendsCount":39339,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416},"senderLocation":point("40.09,92.69"),"sendTime":datetime("2006-08-04T10:10:00"),"referredTopics":{{"motorola","speed"}},"messageText":" can't stand motorola its speed is terrible:("}
+ {"chirpId":"6","user":{"screenName":"ColineGeyer@63","lang":"en","friendsCount":121,"statusesCount":362,"name":"Coline Geyer","followersCount":17159},"senderLocation":point("47.51,83.99"),"sendTime":datetime("2010-05-07T10:10:00"),"referredTopics":{{"iphone","voice-clarity"}},"messageText":" like iphone the voice-clarity is good:)"}
+ {"chirpId":"7","user":{"screenName":"ChangEwing_573","lang":"en","friendsCount":182,"statusesCount":394,"name":"Chang Ewing","followersCount":32136},"senderLocation":point("36.21,72.6"),"sendTime":datetime("2011-08-25T10:10:00"),"referredTopics":{{"samsung","platform"}},"messageText":" like samsung the platform is good"}
+ {"chirpId":"8","user":{"screenName":"NathanGiesen@211","lang":"en","friendsCount":39339,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416},"senderLocation":point("46.05,93.34"),"sendTime":datetime("2005-10-14T10:10:00"),"referredTopics":{{"t-mobile","shortcut-menu"}},"messageText":" like t-mobile the shortcut-menu is awesome:)"}
+ {"chirpId":"9","user":{"screenName":"NathanGiesen@211","lang":"en","friendsCount":39339,"statusesCount":473,"name":"Nathan Giesen","followersCount":49416},"senderLocation":point("36.86,74.62"),"sendTime":datetime("2012-07-21T10:10:00"),"referredTopics":{{"verizon","voicemail-service"}},"messageText":" love verizon its voicemail-service is awesome"}
+ {"chirpId":"10","user":{"screenName":"ColineGeyer@63","lang":"en","friendsCount":121,"statusesCount":362,"name":"Coline Geyer","followersCount":17159},"senderLocation":point("29.15,76.53"),"sendTime":datetime("2008-01-26T10:10:00"),"referredTopics":{{"verizon","voice-clarity"}},"messageText":" hate verizon its voice-clarity is OMG:("}
+ {"chirpId":"11","user":{"screenName":"NilaMilliron_tw","lang":"en","friendsCount":445,"statusesCount":164,"name":"Nila Milliron","followersCount":22649},"senderLocation":point("37.59,68.42"),"sendTime":datetime("2008-03-09T10:10:00"),"referredTopics":{{"iphone","platform"}},"messageText":" can't stand iphone its platform is terrible"}
+ {"chirpId":"12","user":{"screenName":"OliJackson_512","lang":"en","friendsCount":445,"statusesCount":164,"name":"Oli Jackson","followersCount":22649},"senderLocation":point("24.82,94.63"),"sendTime":datetime("2010-02-13T10:10:00"),"referredTopics":{{"samsung","voice-command"}},"messageText":" like samsung the voice-command is amazing:)"}
+</pre></div></div>
+<p><a href="../data/gbu.adm">Gleambook Users</a></p>
+
+<div class="source">
+<div class="source">
+<pre> {"id":1,"alias":"Margarita","name":"MargaritaStoddard","nickname":"Mags","userSince":datetime("2012-08-20T10:10:00"),"friendIds":{{2,3,6,10}},"employment":[{"organizationName":"Codetechno","startDate":date("2006-08-06")},{"organizationName":"geomedia","startDate":date("2010-06-17"),"endDate":date("2010-01-26")}],"gender":"F"}
+ {"id":2,"alias":"Isbel","name":"IsbelDull","nickname":"Izzy","userSince":datetime("2011-01-22T10:10:00"),"friendIds":{{1,4}},"employment":[{"organizationName":"Hexviafind","startDate":date("2010-04-27")}]}
+ {"id":3,"alias":"Emory","name":"EmoryUnk","userSince":datetime("2012-07-10T10:10:00"),"friendIds":{{1,5,8,9}},"employment":[{"organizationName":"geomedia","startDate":date("2010-06-17"),"endDate":date("2010-01-26")}]}
+ {"id":4,"alias":"Nicholas","name":"NicholasStroh","userSince":datetime("2010-12-27T10:10:00"),"friendIds":{{2}},"employment":[{"organizationName":"Zamcorporation","startDate":date("2010-06-08")}]}
+ {"id":5,"alias":"Von","name":"VonKemble","userSince":datetime("2010-01-05T10:10:00"),"friendIds":{{3,6,10}},"employment":[{"organizationName":"Kongreen","startDate":date("2010-11-27")}]}
+ {"id":6,"alias":"Willis","name":"WillisWynne","userSince":datetime("2005-01-17T10:10:00"),"friendIds":{{1,3,7}},"employment":[{"organizationName":"jaydax","startDate":date("2009-05-15")}]}
+ {"id":7,"alias":"Suzanna","name":"SuzannaTillson","userSince":datetime("2012-08-07T10:10:00"),"friendIds":{{6}},"employment":[{"organizationName":"Labzatron","startDate":date("2011-04-19")}]}
+ {"id":8,"alias":"Nila","name":"NilaMilliron","userSince":datetime("2008-01-01T10:10:00"),"friendIds":{{3}},"employment":[{"organizationName":"Plexlane","startDate":date("2010-02-28")}]}
+ {"id":9,"alias":"Woodrow","name":"WoodrowNehling","nickname":"Woody","userSince":datetime("2005-09-20T10:10:00"),"friendIds":{{3,10}},"employment":[{"organizationName":"Zuncan","startDate":date("2003-04-22"),"endDate":date("2009-12-13")}]}
+ {"id":10,"alias":"Bram","name":"BramHatch","userSince":datetime("2010-10-16T10:10:00"),"friendIds":{{1,5,9}},"employment":[{"organizationName":"physcane","startDate":date("2007-06-05"),"endDate":date("2011-11-05")}]}
+</pre></div></div>
+<p><a href="../data/gbm.adm">Gleambook Messages</a></p>
+
+<div class="source">
+<div class="source">
+<pre> {"messageId":1,"authorId":3,"inResponseTo":2,"senderLocation":point("47.16,77.75"),"message":" love sprint its shortcut-menu is awesome:)"}
+ {"messageId":2,"authorId":1,"inResponseTo":4,"senderLocation":point("41.66,80.87"),"message":" dislike iphone its touch-screen is horrible"}
+ {"messageId":3,"authorId":2,"inResponseTo":4,"senderLocation":point("48.09,81.01"),"message":" like samsung the plan is amazing"}
+ {"messageId":4,"authorId":1,"inResponseTo":2,"senderLocation":point("37.73,97.04"),"message":" can't stand at&t the network is horrible:("}
+ {"messageId":5,"authorId":6,"inResponseTo":2,"senderLocation":point("34.7,90.76"),"message":" love sprint the customization is mind-blowing"}
+ {"messageId":6,"authorId":2,"inResponseTo":1,"senderLocation":point("31.5,75.56"),"message":" like t-mobile its platform is mind-blowing"}
+ {"messageId":7,"authorId":5,"inResponseTo":15,"senderLocation":point("32.91,85.05"),"message":" dislike sprint the speed is horrible"}
+ {"messageId":8,"authorId":1,"inResponseTo":11,"senderLocation":point("40.33,80.87"),"message":" like verizon the 3G is awesome:)"}
+ {"messageId":9,"authorId":3,"inResponseTo":12,"senderLocation":point("34.45,96.48"),"message":" love verizon its wireless is good"}
+ {"messageId":10,"authorId":1,"inResponseTo":12,"senderLocation":point("42.5,70.01"),"message":" can't stand motorola the touch-screen is terrible"}
+ {"messageId":11,"authorId":1,"inResponseTo":1,"senderLocation":point("38.97,77.49"),"message":" can't stand at&t its plan is terrible"}
+ {"messageId":12,"authorId":10,"inResponseTo":6,"senderLocation":point("42.26,77.76"),"message":" can't stand t-mobile its voicemail-service is OMG:("}
+ {"messageId":13,"authorId":10,"inResponseTo":4,"senderLocation":point("42.77,78.92"),"message":" dislike iphone the voice-command is bad:("}
+ {"messageId":14,"authorId":9,"inResponseTo":12,"senderLocation":point("41.33,85.28"),"message":" love at&t its 3G is good:)"}
+ {"messageId":15,"authorId":7,"inResponseTo":11,"senderLocation":point("44.47,67.11"),"message":" like iphone the voicemail-service is awesome"}
+</pre></div></div>
+<p>It’s loading time! We can use AQL <i>LOAD</i> statements to populate our datasets with the sample objects shown above. The following shows how loading can be done for data stored in <tt>.adm</tt> files in your local filesystem. <i>Note:</i> You <i>MUST</i> replace the <tt><Host Name></tt> and <tt><Absolute File Path></tt> placeholders in each load statement below with valid values based on the host IP address (or host name) for the machine and directory that you have downloaded the provided <tt>.adm</tt> files to. As you do so, be very, very careful to retain the two slashes in the load statements, i.e., do not delete the two slashes that appear in front of the absolute path to your <tt>.adm</tt> files. (This will lead to a three-slash character sequence at the start of each load statement’s file input path specification.)</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ load dataset GleambookUsers using localfs
+ (("path"="<Host Name>://<Absolute File Path>/gbu.adm"),("format"="adm"));
+
+ load dataset GleambookMessages using localfs
+ (("path"="<Host Name>://<Absolute File Path>/gbm.adm"),("format"="adm"));
+
+ load dataset ChirpUsers using localfs
+ (("path"="<Host Name>://<Absolute File Path>/chu.adm"),("format"="adm"));
+
+ load dataset ChirpMessages using localfs
+ (("path"="<Host Name>://<Absolute File Path>/chm.adm"),("format"="adm"));
+</pre></div></div></div>
+<div class="section">
+<h2><a name="AQL:_Querying_Your_AsterixDB_Data"></a>AQL: Querying Your AsterixDB Data</h2>
+<p>Congratulations! You now have sample social data stored (and indexed) in AsterixDB. (You are part of an elite and adventurous group of individuals. :-)) Now that you have successfully loaded the provided sample data into the datasets that we defined, you can start running queries against them.</p>
+<p>The query language for AsterixDB is AQL—the Asterix Query Language. AQL is loosely based on XQuery, the language developed and standardized in the early to mid 2000’s by the World Wide Web Consortium (W3C) for querying semistructured data stored in their XML format. We have tossed all of the “XML cruft” out of their language but retained many of its core ideas. We did this because its design was developed over a period of years by a diverse committee of smart and experienced language designers, including “SQL people”, “functional programming people”, and “XML people”, all of whom were focused on how to design a new query language that operates well over semistructured data. (We decided to stand on their shoulders instead of starting from scratch and revisiting many of the same issues.) Note that AQL is not SQL and not based on SQL: In other words, AsterixDB is fully “NoSQL compliant”. :-)</p>
+<p>In this section we introduce AQL via a set of example queries, along with their expected results, based on the data above, to help you get started. Many of the most important features of AQL are presented in this set of representative queries. You can find more details in the document on the <a href="datamodel.html">Asterix Data Model (ADM)</a>, in the <a href="manual.html">AQL Reference Manual</a>, and a complete list of built-in functions is available in the <a href="functions.html">Asterix Functions</a> document.</p>
+<p>AQL is an expression language. Even the expression 1+1 is a valid AQL query that evaluates to 2. (Try it for yourself! Okay, maybe that’s <i>not</i> the best use of a 512-node shared-nothing compute cluster.) Most useful AQL queries will be based on the <i>FLWOR</i> (pronounced “flower”) expression structure that AQL has borrowed from XQuery ((<a class="externalLink" href="http://en.wikipedia.org/wiki/FLWOR))">http://en.wikipedia.org/wiki/FLWOR))</a>. The FLWOR expression syntax supports both the incremental binding (<i>for</i>) of variables to ADM data instances in a dataset (or in the result of any AQL expression, actually) and the full binding (<i>let</i>) of variables to entire intermediate results in a fashion similar to temporary views in the SQL world. FLWOR is an acronym that is short for <i>for</i>-<i>let</i>-<i>where</i>-<i>order by</i>-<i>return</i>, naming five of the most frequently used clauses from the syntax of a full AQL query. AQL also includes <i>group by</i> and <i>limit</i> clauses, as you will see shortly. Roughly speaking, for SQL afficiandos, the <i>for</i> clause in AQL is like the <i>from</i> clause in SQL, the <i>return</i> clause in AQL is like the <i>select</i> clause in SQL (but appears at the end instead of the beginning of a query), the <i>let</i> clause in AQL is like SQL’s <i>with</i> clause, and the <i>where</i> and <i>order by</i> clauses in both languages are similar.</p>
+<p>Based on user demand, in order to let SQL afficiandos to write AQL queries in their favored ways, AQL supports a few synonyms: <i>from</i> for <i>for</i>, <i>select</i> for <i>return</i>, <i>with</i> for <i>let</i>, and <i>keeping</i> for <i>with</i> in the group by clause. These have been found to help die-hard SQL fans to feel a little more at home in AQL and to be less likely to (mis)interpret <i>for</i> as imperative looping, <i>return</i> as returning from a function call, and so on.</p>
+<p>Enough talk! Let’s go ahead and try writing some queries and see about learning AQL by example.</p>
+<div class="section">
+<h3><a name="Query_0-A_-_Exact-Match_Lookup"></a>Query 0-A - Exact-Match Lookup</h3>
+<p>For our first query, let’s find a Gleambook user based on his or her user id. Suppose the user we want is the user whose id is 8:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset GleambookUsers
+ where $user.id = 8
+ return $user;
+</pre></div></div>
+<p>The query’s <i>for</i> clause binds the variable <tt>$user</tt> incrementally to the data instances residing in the dataset named GleambookUsers. Its <i>where</i> clause selects only those bindings having a user id of interest, filtering out the rest. The <i>return</i> clause returns the (entire) data instance for each binding that satisfies the predicate. Since this dataset is indexed on user id (its primary key), this query will be done via a quick index lookup.</p>
+<p>The expected result for our sample data is as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "id": 8, "alias": "Nila", "name": "NilaMilliron", "userSince": datetime("2008-01-01T10:10:00.000Z"), "friendIds": {{ 3 }}, "employment": [ { "organizationName": "Plexlane", "startDate": date("2010-02-28") } ] }
+</pre></div></div>
+<p>Note the using the SQL keyword synonyms, another way of phrasing the same query would be:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ from $user in dataset GleambookUsers
+ where $user.id = 8
+ select $user;
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_0-B_-_Range_Scan"></a>Query 0-B - Range Scan</h3>
+<p>AQL, like SQL, supports a variety of different predicates. For example, for our next query, let’s find the Gleambook users whose ids are in the range between 2 and 4:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset GleambookUsers
+ where $user.id >= 2 and $user.id <= 4
+ return $user;
+</pre></div></div>
+<p>This query’s expected result, also evaluable using the primary index on user id, is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "id": 2, "alias": "Isbel", "name": "IsbelDull", "userSince": datetime("2011-01-22T10:10:00.000Z"), "friendIds": {{ 1, 4 }}, "employment": [ { "organizationName": "Hexviafind", "startDate": date("2010-04-27") } ], "nickname": "Izzy" }
+ { "id": 4, "alias": "Nicholas", "name": "NicholasStroh", "userSince": datetime("2010-12-27T10:10:00.000Z"), "friendIds": {{ 2 }}, "employment": [ { "organizationName": "Zamcorporation", "startDate": date("2010-06-08") } ] }
+ { "id": 3, "alias": "Emory", "name": "EmoryUnk", "userSince": datetime("2012-07-10T10:10:00.000Z"), "friendIds": {{ 1, 5, 8, 9 }}, "employment": [ { "organizationName": "geomedia", "startDate": date("2010-06-17"), "endDate": date("2010-01-26") } ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_1_-_Other_Query_Filters"></a>Query 1 - Other Query Filters</h3>
+<p>AQL can do range queries on any data type that supports the appropriate set of comparators. As an example, this next query retrieves the Gleambook users who joined between July 22, 2010 and July 29, 2012:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset GleambookUsers
+ where $user.userSince >= datetime('2010-07-22T00:00:00')
+ and $user.userSince <= datetime('2012-07-29T23:59:59')
+ return $user;
+</pre></div></div>
+<p>The expected result for this query, also an indexable query, is as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "id": 2, "alias": "Isbel", "name": "IsbelDull", "userSince": datetime("2011-01-22T10:10:00.000Z"), "friendIds": {{ 1, 4 }}, "employment": [ { "organizationName": "Hexviafind", "startDate": date("2010-04-27") } ], "nickname": "Izzy" }
+ { "id": 4, "alias": "Nicholas", "name": "NicholasStroh", "userSince": datetime("2010-12-27T10:10:00.000Z"), "friendIds": {{ 2 }}, "employment": [ { "organizationName": "Zamcorporation", "startDate": date("2010-06-08") } ] }
+ { "id": 10, "alias": "Bram", "name": "BramHatch", "userSince": datetime("2010-10-16T10:10:00.000Z"), "friendIds": {{ 1, 5, 9 }}, "employment": [ { "organizationName": "physcane", "startDate": date("2007-06-05"), "endDate": date("2011-11-05") } ] }
+ { "id": 3, "alias": "Emory", "name": "EmoryUnk", "userSince": datetime("2012-07-10T10:10:00.000Z"), "friendIds": {{ 1, 5, 8, 9 }}, "employment": [ { "organizationName": "geomedia", "startDate": date("2010-06-17"), "endDate": date("2010-01-26") } ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_2-A_-_Equijoin"></a>Query 2-A - Equijoin</h3>
+<p>In addition to simply binding variables to data instances and returning them “whole”, an AQL query can construct new ADM instances to return based on combinations of its variable bindings. This gives AQL the power to do joins much like those done using multi-table <i>from</i> clauses in SQL. For example, suppose we wanted a list of all Gleambook users paired with their associated messages, with the list enumerating the author name and the message text associated with each Gleambook message. We could do this as follows in AQL:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset GleambookUsers
+ for $message in dataset GleambookMessages
+ where $message.authorId = $user.id
+ return {
+ "uname": $user.name,
+ "message": $message.message
+ };
+</pre></div></div>
+<p>The result of this query is a sequence of new ADM instances, one for each author/message pair. Each instance in the result will be an ADM object containing two fields, “uname” and “message”, containing the user’s name and the message text, respectively, for each author/message pair. (Note that “uname” and “message” are both simple AQL expressions themselves—so in the most general case, even the resulting field names can be computed as part of the query, making AQL a very powerful tool for slicing and dicing semistructured data.)</p>
+<p>The expected result of this example AQL join query for our sample data set is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "uname": "WillisWynne", "message": " love sprint the customization is mind-blowing" }
+ { "uname": "MargaritaStoddard", "message": " can't stand at&t its plan is terrible" }
+ { "uname": "MargaritaStoddard", "message": " dislike iphone its touch-screen is horrible" }
+ { "uname": "MargaritaStoddard", "message": " can't stand at&t the network is horrible:(" }
+ { "uname": "MargaritaStoddard", "message": " like verizon the 3G is awesome:)" }
+ { "uname": "MargaritaStoddard", "message": " can't stand motorola the touch-screen is terrible" }
+ { "uname": "IsbelDull", "message": " like t-mobile its platform is mind-blowing" }
+ { "uname": "IsbelDull", "message": " like samsung the plan is amazing" }
+ { "uname": "WoodrowNehling", "message": " love at&t its 3G is good:)" }
+ { "uname": "BramHatch", "message": " can't stand t-mobile its voicemail-service is OMG:(" }
+ { "uname": "BramHatch", "message": " dislike iphone the voice-command is bad:(" }
+ { "uname": "EmoryUnk", "message": " love sprint its shortcut-menu is awesome:)" }
+ { "uname": "EmoryUnk", "message": " love verizon its wireless is good" }
+ { "uname": "VonKemble", "message": " dislike sprint the speed is horrible" }
+ { "uname": "SuzannaTillson", "message": " like iphone the voicemail-service is awesome" }
+</pre></div></div>
+<p>Again, as an aside, note that the same query expressed using AQL’s SQL keyword synonyms would be:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ from $user in dataset GleambookUsers
+ from $message in dataset GleambookMessages
+ where $message.authorId = $user.id
+ select {
+ "uname": $user.name,
+ "message": $message.message
+ };
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_2-B_-_Index_join"></a>Query 2-B - Index join</h3>
+<p>By default, AsterixDB evaluates equijoin queries using hash-based join methods that work well for doing ad hoc joins of very large data sets (<a class="externalLink" href="http://en.wikipedia.org/wiki/Hash_join">http://en.wikipedia.org/wiki/Hash_join</a>). On a cluster, hash partitioning is employed as AsterixDB’s divide-and-conquer strategy for computing large parallel joins. AsterixDB includes other join methods, but in the absence of data statistics and selectivity estimates, it doesn’t (yet) have the know-how to intelligently choose among its alternatives. We therefore asked ourselves the classic question—WWOD?—What Would Oracle Do?—and in the interim, AQL includes a clunky (but useful) hint-based mechanism for addressing the occasional need to suggest to AsterixDB which join method it should use for a particular AQL query.</p>
+<p>The following query is similar to Query 2-A but includes a suggestion to AsterixDB that it should consider employing an index-based nested-loop join technique to process the query:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset GleambookUsers
+ for $message in dataset GleambookMessages
+ where $message.authorId /*+ indexnl */ = $user.id
+ return {
+ "uname": $user.name,
+ "message": $message.message
+ };
+</pre></div></div>
+<p>The expected result is (of course) the same as before, modulo the order of the instances. Result ordering is (intentionally) undefined in AQL in the absence of an <i>order by</i> clause. The query result for our sample data in this case is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "uname": "IsbelDull", "message": " like t-mobile its platform is mind-blowing" }
+ { "uname": "MargaritaStoddard", "message": " can't stand at&t its plan is terrible" }
+ { "uname": "BramHatch", "message": " can't stand t-mobile its voicemail-service is OMG:(" }
+ { "uname": "WoodrowNehling", "message": " love at&t its 3G is good:)" }
+ { "uname": "EmoryUnk", "message": " love sprint its shortcut-menu is awesome:)" }
+ { "uname": "MargaritaStoddard", "message": " dislike iphone its touch-screen is horrible" }
+ { "uname": "MargaritaStoddard", "message": " can't stand at&t the network is horrible:(" }
+ { "uname": "BramHatch", "message": " dislike iphone the voice-command is bad:(" }
+ { "uname": "SuzannaTillson", "message": " like iphone the voicemail-service is awesome" }
+ { "uname": "MargaritaStoddard", "message": " like verizon the 3G is awesome:)" }
+ { "uname": "EmoryUnk", "message": " love verizon its wireless is good" }
+ { "uname": "MargaritaStoddard", "message": " can't stand motorola the touch-screen is terrible" }
+ { "uname": "IsbelDull", "message": " like samsung the plan is amazing" }
+ { "uname": "WillisWynne", "message": " love sprint the customization is mind-blowing" }
+ { "uname": "VonKemble", "message": " dislike sprint the speed is horrible" }
+</pre></div></div>
+<p>(It is worth knowing, with respect to influencing AsterixDB’s query evaluation, that nested <i>for</i> clauses—a.k.a. joins— are currently evaluated with the “outer” clause probing the data of the “inner” clause.)</p></div>
+<div class="section">
+<h3><a name="Query_3_-_Nested_Outer_Join"></a>Query 3 - Nested Outer Join</h3>
+<p>In order to support joins between tables with missing/dangling join tuples, the designers of SQL ended up shoe-horning a subset of the relational algebra into SQL’s <i>from</i> clause syntax—and providing a variety of join types there for users to choose from. Left outer joins are particularly important in SQL, e.g., to print a summary of customers and orders, grouped by customer, without omitting those customers who haven’t placed any orders yet.</p>
+<p>The AQL language supports nesting, both of queries and of query results, and the combination allows for an arguably cleaner/more natural approach to such queries. As an example, supposed we wanted, for each Gleambook user, to produce a object that has his/her name plus a list of the messages written by that user. In SQL, this would involve a left outer join between users and messages, grouping by user, and having the user name repeated along side each message. In AQL, this sort of use case can be handled (more naturally) as follows:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset GleambookUsers
+ return {
+ "uname": $user.name,
+ "messages": for $message in dataset GleambookMessages
+ where $message.authorId = $user.id
+ return $message.message
+ };
+</pre></div></div>
+<p>This AQL query binds the variable <tt>$user</tt> to the data instances in GleambookUsers; for each user, it constructs a result object containing a “uname” field with the user’s name and a “messages” field with a nested collection of all messages for that user. The nested collection for each user is specified by using a correlated subquery. (Note: While it looks like nested loops could be involved in computing the result, AsterixDB recogizes the equivalence of such a query to an outerjoin, and it will use an efficient hash-based strategy when actually computing the query’s result.)</p>
+<p>Here is this example query’s expected output:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "uname": "WillisWynne", "messages": [ " love sprint the customization is mind-blowing" ] }
+ { "uname": "MargaritaStoddard", "messages": [ " can't stand at&t its plan is terrible", " dislike iphone its touch-screen is horrible", " can't stand at&t the network is horrible:(", " like verizon the 3G is awesome:)", " can't stand motorola the touch-screen is terrible" ] }
+ { "uname": "IsbelDull", "messages": [ " like t-mobile its platform is mind-blowing", " like samsung the plan is amazing" ] }
+ { "uname": "NicholasStroh", "messages": [ ] }
+ { "uname": "NilaMilliron", "messages": [ ] }
+ { "uname": "WoodrowNehling", "messages": [ " love at&t its 3G is good:)" ] }
+ { "uname": "BramHatch", "messages": [ " can't stand t-mobile its voicemail-service is OMG:(", " dislike iphone the voice-command is bad:(" ] }
+ { "uname": "EmoryUnk", "messages": [ " love sprint its shortcut-menu is awesome:)", " love verizon its wireless is good" ] }
+ { "uname": "VonKemble", "messages": [ " dislike sprint the speed is horrible" ] }
+ { "uname": "SuzannaTillson", "messages": [ " like iphone the voicemail-service is awesome" ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_4_-_Theta_Join"></a>Query 4 - Theta Join</h3>
+<p>Not all joins are expressible as equijoins and computable using equijoin-oriented algorithms. The join predicates for some use cases involve predicates with functions; AsterixDB supports the expression of such queries and will still evaluate them as best it can using nested loop based techniques (and broadcast joins in the parallel case).</p>
+<p>As an example of such a use case, suppose that we wanted, for each chirp T, to find all of the other chirps that originated from within a circle of radius of 1 surrounding chirp T’s location. In AQL, this can be specified in a manner similar to the previous query using one of the built-in functions on the spatial data type instead of id equality in the correlated query’s <i>where</i> clause:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $cm in dataset ChirpMessages
+ return {
+ "message": $cm.messageText,
+ "nearbyMessages": for $cm2 in dataset ChirpMessages
+ where spatial-distance($cm.senderLocation, $cm2.senderLocation) <= 1
+ return { "msgtxt":$cm2.messageText}
+ };
+</pre></div></div>
+<p>Here is the expected result for this query:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "message": " can't stand iphone its platform is terrible", "nearbyMessages": [ { "msgtxt": " can't stand iphone its platform is terrible" } ] }
+ { "message": " like verizon its shortcut-menu is awesome:)", "nearbyMessages": [ { "msgtxt": " like verizon its shortcut-menu is awesome:)" } ] }
+ { "message": " like sprint the voice-command is mind-blowing:)", "nearbyMessages": [ { "msgtxt": " like sprint the voice-command is mind-blowing:)" } ] }
+ { "message": " love verizon its voicemail-service is awesome", "nearbyMessages": [ { "msgtxt": " love verizon its voicemail-service is awesome" } ] }
+ { "message": " love t-mobile its customization is good:)", "nearbyMessages": [ { "msgtxt": " love t-mobile its customization is good:)" } ] }
+ { "message": " can't stand motorola its speed is terrible:(", "nearbyMessages": [ { "msgtxt": " can't stand motorola its speed is terrible:(" } ] }
+ { "message": " like motorola the speed is good:)", "nearbyMessages": [ { "msgtxt": " like motorola the speed is good:)" }, { "msgtxt": " hate verizon its voice-clarity is OMG:(" } ] }
+ { "message": " like iphone the voice-clarity is good:)", "nearbyMessages": [ { "msgtxt": " like iphone the voice-clarity is good:)" } ] }
+ { "message": " like samsung the platform is good", "nearbyMessages": [ { "msgtxt": " like samsung the platform is good" } ] }
+ { "message": " hate verizon its voice-clarity is OMG:(", "nearbyMessages": [ { "msgtxt": " like motorola the speed is good:)" }, { "msgtxt": " hate verizon its voice-clarity is OMG:(" } ] }
+ { "message": " like samsung the voice-command is amazing:)", "nearbyMessages": [ { "msgtxt": " like samsung the voice-command is amazing:)" } ] }
+ { "message": " like t-mobile the shortcut-menu is awesome:)", "nearbyMessages": [ { "msgtxt": " like t-mobile the shortcut-menu is awesome:)" } ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_5_-_Fuzzy_Join"></a>Query 5 - Fuzzy Join</h3>
+<p>As another example of a non-equijoin use case, we could ask AsterixDB to find, for each Gleambook user, all Chirp users with names “similar” to their name. AsterixDB supports a variety of “fuzzy match” functions for use with textual and set-based data. As one example, we could choose to use edit distance with a threshold of 3 as the definition of name similarity, in which case we could write the following query using AQL’s operator-based syntax (~=) for testing whether or not two values are similar:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ set simfunction "edit-distance";
+ set simthreshold "3";
+
+ for $gbu in dataset GleambookUsers
+ return {
+ "id": $gbu.id,
+ "name": $gbu.name,
+ "similarUsers": for $cm in dataset ChirpMessages
+ let $cu := $cm.user
+ where $cu.name ~= $gbu.name
+ return {
+ "chirpScreenname": $cu.screenName,
+ "chirpName": $cu.name
+ }
+ };
+</pre></div></div>
+<p>The expected result for this query against our sample data is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "id": 6, "name": "WillisWynne", "similarUsers": [ ] }
+ { "id": 1, "name": "MargaritaStoddard", "similarUsers": [ ] }
+ { "id": 2, "name": "IsbelDull", "similarUsers": [ ] }
+ { "id": 4, "name": "NicholasStroh", "similarUsers": [ ] }
+ { "id": 8, "name": "NilaMilliron", "similarUsers": [ { "chirpScreenname": "NilaMilliron_tw", "chirpName": "Nila Milliron" } ] }
+ { "id": 9, "name": "WoodrowNehling", "similarUsers": [ ] }
+ { "id": 10, "name": "BramHatch", "similarUsers": [ ] }
+ { "id": 3, "name": "EmoryUnk", "similarUsers": [ ] }
+ { "id": 5, "name": "VonKemble", "similarUsers": [ ] }
+ { "id": 7, "name": "SuzannaTillson", "similarUsers": [ ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_6_-_Existential_Quantification"></a>Query 6 - Existential Quantification</h3>
+<p>The expressive power of AQL includes support for queries involving “some” (existentially quantified) and “all” (universally quantified) query semantics. As an example of an existential AQL query, here we show a query to list the Gleambook users who are currently employed. Such employees will have an employment history containing a object with the endDate value missing, which leads us to the following AQL query:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $gbu in dataset GleambookUsers
+ where (some $e in $gbu.employment satisfies is-missing($e.endDate))
+ return $gbu;
+</pre></div></div>
+<p>The expected result in this case is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "id": 6, "alias": "Willis", "name": "WillisWynne", "userSince": datetime("2005-01-17T10:10:00.000Z"), "friendIds": {{ 1, 3, 7 }}, "employment": [ { "organizationName": "jaydax", "startDate": date("2009-05-15") } ] }
+ { "id": 1, "alias": "Margarita", "name": "MargaritaStoddard", "userSince": datetime("2012-08-20T10:10:00.000Z"), "friendIds": {{ 2, 3, 6, 10 }}, "employment": [ { "organizationName": "Codetechno", "startDate": date("2006-08-06") }, { "organizationName": "geomedia", "startDate": date("2010-06-17"), "endDate": date("2010-01-26") } ], "nickname": "Mags", "gender": "F" }
+ { "id": 2, "alias": "Isbel", "name": "IsbelDull", "userSince": datetime("2011-01-22T10:10:00.000Z"), "friendIds": {{ 1, 4 }}, "employment": [ { "organizationName": "Hexviafind", "startDate": date("2010-04-27") } ], "nickname": "Izzy" }
+ { "id": 4, "alias": "Nicholas", "name": "NicholasStroh", "userSince": datetime("2010-12-27T10:10:00.000Z"), "friendIds": {{ 2 }}, "employment": [ { "organizationName": "Zamcorporation", "startDate": date("2010-06-08") } ] }
+ { "id": 8, "alias": "Nila", "name": "NilaMilliron", "userSince": datetime("2008-01-01T10:10:00.000Z"), "friendIds": {{ 3 }}, "employment": [ { "organizationName": "Plexlane", "startDate": date("2010-02-28") } ] }
+ { "id": 5, "alias": "Von", "name": "VonKemble", "userSince": datetime("2010-01-05T10:10:00.000Z"), "friendIds": {{ 3, 6, 10 }}, "employment": [ { "organizationName": "Kongreen", "startDate": date("2010-11-27") } ] }
+ { "id": 7, "alias": "Suzanna", "name": "SuzannaTillson", "userSince": datetime("2012-08-07T10:10:00.000Z"), "friendIds": {{ 6 }}, "employment": [ { "organizationName": "Labzatron", "startDate": date("2011-04-19") } ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_7_-_Universal_Quantification"></a>Query 7 - Universal Quantification</h3>
+<p>As an example of a universal AQL query, here we show a query to list the Gleambook users who are currently unemployed. Such employees will have an employment history containing no objects that miss endDate values, leading us to the following AQL query:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $gbu in dataset GleambookUsers
+ where (every $e in $gbu.employment satisfies not(is-missing($e.endDate)))
+ return $gbu;
+</pre></div></div>
+<p>Here is the expected result for our sample data:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "id": 9, "alias": "Woodrow", "name": "WoodrowNehling", "userSince": datetime("2005-09-20T10:10:00.000Z"), "friendIds": {{ 3, 10 }}, "employment": [ { "organizationName": "Zuncan", "startDate": date("2003-04-22"), "endDate": date("2009-12-13") } ], "nickname": "Woody" }
+ { "id": 10, "alias": "Bram", "name": "BramHatch", "userSince": datetime("2010-10-16T10:10:00.000Z"), "friendIds": {{ 1, 5, 9 }}, "employment": [ { "organizationName": "physcane", "startDate": date("2007-06-05"), "endDate": date("2011-11-05") } ] }
+ { "id": 3, "alias": "Emory", "name": "EmoryUnk", "userSince": datetime("2012-07-10T10:10:00.000Z"), "friendIds": {{ 1, 5, 8, 9 }}, "employment": [ { "organizationName": "geomedia", "startDate": date("2010-06-17"), "endDate": date("2010-01-26") } ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_8_-_Simple_Aggregation"></a>Query 8 - Simple Aggregation</h3>
+<p>Like SQL, the AQL language of AsterixDB provides support for computing aggregates over large amounts of data. As a very simple example, the following AQL query computes the total number of Gleambook users:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ count(for $gbu in dataset GleambookUsers return $gbu);
+</pre></div></div>
+<p>In AQL, aggregate functions can be applied to arbitrary subquery results; in this case, the count function is applied to the result of a query that enumerates the Gleambook users. The expected result here is:</p>
+
+<div class="source">
+<div class="source">
+<pre> 10
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_9-A_-_Grouping_and_Aggregation"></a>Query 9-A - Grouping and Aggregation</h3>
+<p>Also like SQL, AQL supports grouped aggregation. For every Chirp user, the following group-by/aggregate query counts the number of chirps sent by that user:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $cm in dataset ChirpMessages
+ group by $uid := $cm.user.screenName with $cm
+ return {
+ "user": $uid,
+ "count": count($cm)
+ };
+</pre></div></div>
+<p>The <i>for</i> clause incrementally binds $cm to chirps, and the <i>group by</i> clause groups the chirps by its issuer’s Chirp screenName. Unlike SQL, where data is tabular—flat—the data model underlying AQL allows for nesting. Thus, following the <i>group by</i> clause, the <i>return</i> clause in this query sees a sequence of $cm groups, with each such group having an associated $uid variable value (i.e., the chirping user’s screen name). In the context of the return clause, due to “… with $cm …”, $uid is bound to the chirper’s id and $cm is bound to the <i>set</i> of chirps issued by that chirper. The return clause constructs a result object containing the chirper’s user id and the count of the items in the associated chirp set. The query result will contain one such object per screen name. This query also illustrates another feature of AQL; notice that each user’s screen name is accessed via a path syntax that traverses each chirp’s nested object structure.</p>
+<p>Here is the expected result for this query over the sample data:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "user": "OliJackson_512", "count": 1 }
+ { "user": "ChangEwing_573", "count": 1 }
+ { "user": "ColineGeyer@63", "count": 3 }
+ { "user": "NathanGiesen@211", "count": 6 }
+ { "user": "NilaMilliron_tw", "count": 1 }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_9-B_-_Hash-Based_Grouping_and_Aggregation"></a>Query 9-B - (Hash-Based) Grouping and Aggregation</h3>
+<p>As for joins, AsterixDB has multiple evaluation strategies available for processing grouped aggregate queries. For grouped aggregation, the system knows how to employ both sort-based and hash-based aggregation methods, with sort-based methods being used by default and a hint being available to suggest that a different approach be used in processing a particular AQL query.</p>
+<p>The following query is similar to Query 9-A, but adds a hash-based aggregation hint:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $cm in dataset ChirpMessages
+ /*+ hash*/
+ group by $uid := $cm.user.screenName with $cm
+ return {
+ "user": $uid,
+ "count": count($cm)
+ };
+</pre></div></div>
+<p>Here is the expected result:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "user": "OliJackson_512", "count": 1 }
+ { "user": "ChangEwing_573", "count": 1 }
+ { "user": "ColineGeyer@63", "count": 3 }
+ { "user": "NathanGiesen@211", "count": 6 }
+ { "user": "NilaMilliron_tw", "count": 1 }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_10_-_Grouping_and_Limits"></a>Query 10 - Grouping and Limits</h3>
+<p>In some use cases it is not necessary to compute the entire answer to a query. In some cases, just having the first <i>N</i> or top <i>N</i> results is sufficient. This is expressible in AQL using the <i>limit</i> clause combined with the <i>order by</i> clause.</p>
+<p>The following AQL query returns the top 3 Chirp users based on who has issued the most chirps:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $cm in dataset ChirpMessages
+ group by $uid := $cm.user.screenName with $cm
+ let $c := count($cm)
+ order by $c desc
+ limit 3
+ return {
+ "user": $uid,
+ "count": $c
+ };
+</pre></div></div>
+<p>The expected result for this query is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "user": "NathanGiesen@211", "count": 6 }
+ { "user": "ColineGeyer@63", "count": 3 }
+ { "user": "OliJackson_512", "count": 1 }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Query_11_-_Left_Outer_Fuzzy_Join"></a>Query 11 - Left Outer Fuzzy Join</h3>
+<p>As a last example of AQL and its query power, the following query, for each chirp, finds all of the chirps that are similar based on the topics that they refer to:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ set simfunction "jaccard";
+ set simthreshold "0.3";
+
+ for $cm in dataset ChirpMessages
+ return {
+ "chirp": $cm,
+ "similarChirps": for $cm2 in dataset ChirpMessages
+ where $cm2.referredTopics ~= $cm.referredTopics
+ and $cm2.chirpId != $cm.chirpId
+ return $cm2.referredTopics
+ };
+</pre></div></div>
+<p>This query illustrates several things worth knowing in order to write fuzzy queries in AQL. First, as mentioned earlier, AQL offers an operator-based syntax for seeing whether two values are “similar” to one another or not. Second, recall that the referredTopics field of objects of datatype ChirpMessageType is a bag of strings. This query sets the context for its similarity join by requesting that Jaccard-based similarity semantics (<a class="externalLink" href="http://en.wikipedia.org/wiki/Jaccard_index">http://en.wikipedia.org/wiki/Jaccard_index</a>) be used for the query’s similarity operator and that a similarity index of 0.3 be used as its similarity threshold.</p>
+<p>The expected result for this fuzzy join query is:</p>
+
+<div class="source">
+<div class="source">
+<pre> { "chirp": { "chirpId": "11", "user": { "screenName": "NilaMilliron_tw", "lang": "en", "friendsCount": 445, "statusesCount": 164, "name": "Nila Milliron", "followersCount": 22649 }, "senderLocation": point("37.59,68.42"), "sendTime": datetime("2008-03-09T10:10:00.000Z"), "referredTopics": {{ "iphone", "platform" }}, "messageText": " can't stand iphone its platform is terrible" }, "similarChirps": [ {{ "iphone", "voice-clarity" }}, {{ "samsung", "platform" }} ] }
+ { "chirp": { "chirpId": "2", "user": { "screenName": "ColineGeyer@63", "lang": "en", "friendsCount": 121, "statusesCount": 362, "name": "Coline Geyer", "followersCount": 17159 }, "senderLocation": point("32.84,67.14"), "sendTime": datetime("2010-05-13T10:10:00.000Z"), "referredTopics": {{ "verizon", "shortcut-menu" }}, "messageText": " like verizon its shortcut-menu is awesome:)" }, "similarChirps": [ {{ "verizon", "voicemail-service" }}, {{ "verizon", "voice-clarity" }}, {{ "t-mobile", "shortcut-menu" }} ] }
+ { "chirp": { "chirpId": "4", "user": { "screenName": "NathanGiesen@211", "lang": "en", "friendsCount": 39339, "statusesCount": 473, "name": "Nathan Giesen", "followersCount": 49416 }, "senderLocation": point("39.28,70.48"), "sendTime": datetime("2011-12-26T10:10:00.000Z"), "referredTopics": {{ "sprint", "voice-command" }}, "messageText": " like sprint the voice-command is mind-blowing:)" }, "similarChirps": [ {{ "samsung", "voice-command" }} ] }
+ { "chirp": { "chirpId": "9", "user": { "screenName": "NathanGiesen@211", "lang": "en", "friendsCount": 39339, "statusesCount": 473, "name": "Nathan Giesen", "followersCount": 49416 }, "senderLocation": point("36.86,74.62"), "sendTime": datetime("2012-07-21T10:10:00.000Z"), "referredTopics": {{ "verizon", "voicemail-service" }}, "messageText": " love verizon its voicemail-service is awesome" }, "similarChirps": [ {{ "verizon", "shortcut-menu" }}, {{ "verizon", "voice-clarity" }} ] }
+ { "chirp": { "chirpId": "1", "user": { "screenName": "NathanGiesen@211", "lang": "en", "friendsCount": 39339, "statusesCount": 473, "name": "Nathan Giesen", "followersCount": 49416 }, "senderLocation": point("47.44,80.65"), "sendTime": datetime("2008-04-26T10:10:00.000Z"), "referredTopics": {{ "t-mobile", "customization" }}, "messageText": " love t-mobile its customization is good:)" }, "similarChirps": [ {{ "t-mobile", "shortcut-menu" }} ] }
+ { "chirp": { "chirpId": "5", "user": { "screenName": "NathanGiesen@211", "lang": "en", "friendsCount": 39339, "statusesCount": 473, "name": "Nathan Giesen", "followersCount": 49416 }, "senderLocation": point("40.09,92.69"), "sendTime": datetime("2006-08-04T10:10:00.000Z"), "referredTopics": {{ "motorola", "speed" }}, "messageText": " can't stand motorola its speed is terrible:(" }, "similarChirps": [ {{ "motorola", "speed" }} ] }
+ { "chirp": { "chirpId": "3", "user": { "screenName": "NathanGiesen@211", "lang": "en", "friendsCount": 39339, "statusesCount": 473, "name": "Nathan Giesen", "followersCount": 49416 }, "senderLocation": point("29.72,75.8"), "sendTime": datetime("2006-11-04T10:10:00.000Z"), "referredTopics": {{ "motorola", "speed" }}, "messageText": " like motorola the speed is good:)" }, "similarChirps": [ {{ "motorola", "speed" }} ] }
+ { "chirp": { "chirpId": "6", "user": { "screenName": "ColineGeyer@63", "lang": "en", "friendsCount": 121, "statusesCount": 362, "name": "Coline Geyer", "followersCount": 17159 }, "senderLocation": point("47.51,83.99"), "sendTime": datetime("2010-05-07T10:10:00.000Z"), "referredTopics": {{ "iphone", "voice-clarity" }}, "messageText": " like iphone the voice-clarity is good:)" }, "similarChirps": [ {{ "iphone", "platform" }}, {{ "verizon", "voice-clarity" }} ] }
+ { "chirp": { "chirpId": "7", "user": { "screenName": "ChangEwing_573", "lang": "en", "friendsCount": 182, "statusesCount": 394, "name": "Chang Ewing", "followersCount": 32136 }, "senderLocation": point("36.21,72.6"), "sendTime": datetime("2011-08-25T10:10:00.000Z"), "referredTopics": {{ "samsung", "platform" }}, "messageText": " like samsung the platform is good" }, "similarChirps": [ {{ "iphone", "platform" }}, {{ "samsung", "voice-command" }} ] }
+ { "chirp": { "chirpId": "10", "user": { "screenName": "ColineGeyer@63", "lang": "en", "friendsCount": 121, "statusesCount": 362, "name": "Coline Geyer", "followersCount": 17159 }, "senderLocation": point("29.15,76.53"), "sendTime": datetime("2008-01-26T10:10:00.000Z"), "referredTopics": {{ "verizon", "voice-clarity" }}, "messageText": " hate verizon its voice-clarity is OMG:(" }, "similarChirps": [ {{ "verizon", "shortcut-menu" }}, {{ "verizon", "voicemail-service" }}, {{ "iphone", "voice-clarity" }} ] }
+ { "chirp": { "chirpId": "12", "user": { "screenName": "OliJackson_512", "lang": "en", "friendsCount": 445, "statusesCount": 164, "name": "Oli Jackson", "followersCount": 22649 }, "senderLocation": point("24.82,94.63"), "sendTime": datetime("2010-02-13T10:10:00.000Z"), "referredTopics": {{ "samsung", "voice-command" }}, "messageText": " like samsung the voice-command is amazing:)" }, "similarChirps": [ {{ "sprint", "voice-command" }}, {{ "samsung", "platform" }} ] }
+ { "chirp": { "chirpId": "8", "user": { "screenName": "NathanGiesen@211", "lang": "en", "friendsCount": 39339, "statusesCount": 473, "name": "Nathan Giesen", "followersCount": 49416 }, "senderLocation": point("46.05,93.34"), "sendTime": datetime("2005-10-14T10:10:00.000Z"), "referredTopics": {{ "t-mobile", "shortcut-menu" }}, "messageText": " like t-mobile the shortcut-menu is awesome:)" }, "similarChirps": [ {{ "verizon", "shortcut-menu" }}, {{ "t-mobile", "customization" }} ] }
+</pre></div></div></div>
+<div class="section">
+<h3><a name="Inserting_New_Data"></a>Inserting New Data</h3>
+<p>In addition to loading and querying data, AsterixDB supports incremental additions to datasets via the AQL <i>insert</i> statement.</p>
+<p>The following example adds a new chirp by user “<a class="externalLink" href="mailto:NathanGiesen@211">NathanGiesen@211</a>” to the ChirpMessages dataset. (An astute reader may notice that this chirp was issued a half an hour after his last chirp, so his counts have all gone up in the interim, although he appears not to have moved in the last half hour.)</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ insert into dataset ChirpMessages
+ (
+ {"chirpId": "13",
+ "user":
+ {"screenName": "NathanGiesen@211",
+ "lang": "en",
+ "friendsCount": 39345,
+ "statusesCount": 479,
+ "name": "Nathan Giesen",
+ "followersCount": 49420
+ },
+ "senderLocation": point("47.44,80.65"),
+ "sendTime": datetime("2008-04-26T10:10:35"),
+ "referredTopics": {{"chirping"}},
+ "messageText": "chirpy chirp, my fellow chirpers!"
+ }
+ );
+</pre></div></div>
+<p>In general, the data to be inserted may be specified using any valid AQL query expression. The insertion of a single object instance, as in this example, is just a special case where the query expression happens to be a object constructor involving only constants.</p></div>
+<div class="section">
+<h3><a name="Deleting_Existing_Data"></a>Deleting Existing Data</h3>
+<p>In addition to inserting new data, AsterixDB supports deletion from datasets via the AQL <i>delete</i> statement. The statement supports “searched delete” semantics, and its <i>where</i> clause can involve any valid XQuery expression.</p>
+<p>The following example deletes the chirp that we just added from user "<a class="externalLink" href="mailto:NathanGiesen@211"">NathanGiesen@211"</a>. (Easy come, easy go. :-))</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ delete $cm from dataset ChirpMessages where $cm.chirpId = "13";
+</pre></div></div>
+<p>It should be noted that one form of data change not yet supported by AsterixDB is in-place data modification (<i>update</i>). Currently, only insert and delete operations are supported; update is not. To achieve the effect of an update, two statements are currently needed—one to delete the old object from the dataset where it resides, and another to insert the new replacement object (with the same primary key but with different field values for some of the associated data content).</p></div>
+<div class="section">
+<h3><a name="Upserting_Data"></a>Upserting Data</h3>
+<p>In addition to loading, querying, inserting, and deleting data, AsterixDB supports upserting objects using the AQL <i>upsert</i> statement.</p>
+<p>The following example deletes the chirp with chirpId = 20 (if one exists) and inserts the new chirp with chirpId = 20 by user “SwanSmitty” to the ChirpMessages dataset. The two operations (delete if found and insert) are performed as an atomic operation that is either performed completely or not at all.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+ upsert into dataset ChirpMessages
+ (
+ {"chirpId": "20",
+ "user":
+ {"screenName": "SwanSmitty",
+ "lang": "en",
+ "friendsCount": 91345,
+ "statusesCount": 4079,
+ "name": "Swanson Smith",
+ "followersCount": 50420
+ },
+ "senderLocation": point("47.44,80.65"),
+ "sendTime": datetime("2008-04-26T10:10:35"),
+ "referredTopics": {{"football"}},
+ "messageText": "football is the best sport, period.!"
+ }
+ );
+</pre></div></div>
+<p>The data to be upserted may be specified using any valid AQL query expression. For example, the following statement might be used to double the followers count of all existing users.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+ upsert into dataset ChirpUsers
+ (
+ for $user in dataset ChirpUsers
+ return {
+ "screenName": $user.screenName,
+ "lang": $user.lang,
+ "friendsCount": $user.friendsCount,
+ "statusesCount": $user.statusesCount,
+ "name": $user.name,
+ "followersCount": $user.followersCount * 2
+ }
+ );
+</pre></div></div>
+<p>Note that such an upsert operation is executed in two steps: The query is performed, after which the query’s locks are released, and then its result is upserted into the dataset. This means that a object can be modified between computing the query result and performing the upsert.</p></div>
+<div class="section">
+<h3><a name="Transaction_Support"></a>Transaction Support</h3>
+<p>AsterixDB supports object-level ACID transactions that begin and terminate implicitly for each object inserted, deleted, or searched while a given AQL statement is being executed. This is quite similar to the level of transaction support found in today’s NoSQL stores. AsterixDB does not support multi-statement transactions, and in fact an AQL statement that involves multiple objects can itself involve multiple independent object-level transactions. An example consequence of this is that, when an AQL statement attempts to insert 1000 objects, it is possible that the first 800 objects could end up being committed while the remaining 200 objects fail to be inserted. This situation could happen, for example, if a duplicate key exception occurs as the 801st insertion is attempted. If this happens, AsterixDB will report the error (e.g., a duplicate key exception) as the result of the offending AQL insert statement, and the application logic above will need to take the appropriate action(s) needed to assess the resulting state and to clean up and/or continue as appropriate.</p></div></div>
+<div class="section">
+<h2><a name="Further_Help"></a>Further Help</h2>
+<p>That’s it! You are now armed and dangerous with respect to semistructured data management using AsterixDB and AQL.</p>
+<p>AsterixDB is a powerful new BDMS—Big Data Management System—that we hope may usher in a new era of much more declarative Big Data management. AsterixDB is powerful, so use it wisely, and remember: “With great power comes great responsibility…” :-)</p>
+<p>Please e-mail the AsterixDB user group (users (at) asterixdb.apache.org) if you run into any problems or simply have further questions about the AsterixDB system, its features, or their proper use.</p></div>
+ </div>
+ </div>
+ </div>
+
+ <hr/>
+
+ <footer>
+ <div class="container-fluid">
+ <div class="row span12">Copyright © 2017
+ <a href="https://www.apache.org/">The Apache Software Foundation</a>.
+ All Rights Reserved.
+
+ </div>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<div class="row-fluid">Apache AsterixDB, AsterixDB, Apache, the Apache
+ feather logo, and the Apache AsterixDB project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.</div>
+
+
+ </div>
+ </footer>
+ </body>
+</html>
diff --git a/docs/0.9.0/aql/similarity.html b/docs/0.9.0/aql/similarity.html
new file mode 100644
index 0000000..32cf5e0
--- /dev/null
+++ b/docs/0.9.0/aql/similarity.html
@@ -0,0 +1,451 @@
+<!DOCTYPE html>
+<!--
+ | Generated by Apache Maven Doxia at 2017-01-24
+ | Rendered using Apache Maven Fluido Skin 1.3.0
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="Date-Revision-yyyymmdd" content="20170124" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>AsterixDB – AsterixDB Support of Similarity Queries</title>
+ <link rel="stylesheet" href="../css/apache-maven-fluido-1.3.0.min.css" />
+ <link rel="stylesheet" href="../css/site.css" />
+ <link rel="stylesheet" href="../css/print.css" media="print" />
+
+
+ <script type="text/javascript" src="../js/apache-maven-fluido-1.3.0.min.js"></script>
+
+
+
+<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-41536543-1', 'uci.edu');
+ ga('send', 'pageview');</script>
+
+ </head>
+ <body class="topBarDisabled">
+
+
+
+
+ <div class="container-fluid">
+ <div id="banner">
+ <div class="pull-left">
+ <a href=".././" id="bannerLeft">
+ <img src="../images/asterixlogo.png" alt="AsterixDB"/>
+ </a>
+ </div>
+ <div class="pull-right"> </div>
+ <div class="clear"><hr/></div>
+ </div>
+
+ <div id="breadcrumbs">
+ <ul class="breadcrumb">
+
+
+ <li id="publishDate">Last Published: 2017-01-24</li>
+
+
+
+ <li id="projectVersion" class="pull-right">Version: 0.9.0</li>
+
+ <li class="divider pull-right">|</li>
+
+ <li class="pull-right"> <a href="../index.html" title="Documentation Home">
+ Documentation Home</a>
+ </li>
+
+ </ul>
+ </div>
+
+
+ <div class="row-fluid">
+ <div id="leftColumn" class="span3">
+ <div class="well sidebar-nav">
+
+
+ <ul class="nav nav-list">
+ <li class="nav-header">Get Started - Installation</li>
+
+ <li>
+
+ <a href="../ncservice.html" title="Option 1: using NCService">
+ <i class="none"></i>
+ Option 1: using NCService</a>
+ </li>
+
+ <li>
+
+ <a href="../install.html" title="Option 2: using Managix">
+ <i class="none"></i>
+ Option 2: using Managix</a>
+ </li>
+
+ <li>
+
+ <a href="../yarn.html" title="Option 3: using YARN">
+ <i class="none"></i>
+ Option 3: using YARN</a>
+ </li>
+ <li class="nav-header">AsterixDB Primer</li>
+
+ <li>
+
+ <a href="../sqlpp/primer-sqlpp.html" title="Option 1: using SQL++">
+ <i class="none"></i>
+ Option 1: using SQL++</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/primer.html" title="Option 2: using AQL">
+ <i class="none"></i>
+ Option 2: using AQL</a>
+ </li>
+ <li class="nav-header">Data Model</li>
+
+ <li>
+
+ <a href="../datamodel.html" title="The Asterix Data Model">
+ <i class="none"></i>
+ The Asterix Data Model</a>
+ </li>
+ <li class="nav-header">Queries - SQL++</li>
+
+ <li>
+
+ <a href="../sqlpp/manual.html" title="The SQL++ Query Language">
+ <i class="none"></i>
+ The SQL++ Query Language</a>
+ </li>
+
+ <li>
+
+ <a href="../sqlpp/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Queries - AQL</li>
+
+ <li>
+
+ <a href="../aql/manual.html" title="The Asterix Query Language (AQL)">
+ <i class="none"></i>
+ The Asterix Query Language (AQL)</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/builtins.html" title="Builtin Functions">
+ <i class="none"></i>
+ Builtin Functions</a>
+ </li>
+ <li class="nav-header">Advanced Features</li>
+
+ <li class="active">
+
+ <a href="#"><i class="none"></i>Support of Similarity Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/fulltext.html" title="Support of Full-text Queries">
+ <i class="none"></i>
+ Support of Full-text Queries</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/externaldata.html" title="Accessing External Data">
+ <i class="none"></i>
+ Accessing External Data</a>
+ </li>
+
+ <li>
+
+ <a href="../feeds/tutorial.html" title="Support for Data Ingestion">
+ <i class="none"></i>
+ Support for Data Ingestion</a>
+ </li>
+
+ <li>
+
+ <a href="../udf.html" title="User Defined Functions">
+ <i class="none"></i>
+ User Defined Functions</a>
+ </li>
+
+ <li>
+
+ <a href="../aql/filters.html" title="Filter-Based LSM Index Acceleration">
+ <i class="none"></i>
+ Filter-Based LSM Index Acceleration</a>
+ </li>
+ <li class="nav-header">API/SDK</li>
+
+ <li>
+
+ <a href="../api.html" title="HTTP API">
+ <i class="none"></i>
+ HTTP API</a>
+ </li>
+ </ul>
+
+
+
+ <hr class="divider" />
+
+ <div id="poweredBy">
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <div class="clear"></div>
+ <a href=".././" title="AsterixDB" class="builtBy">
+ <img class="builtBy" alt="AsterixDB" src="../images/asterixlogo.png" />
+ </a>
+ </div>
+ </div>
+ </div>
+
+
+ <div id="bodyColumn" class="span9" >
+
+ <!-- ! 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.
+ ! --><h1>AsterixDB Support of Similarity Queries</h1>
+<div class="section">
+<h2><a name="Table_of_Contents"></a><a name="toc" id="toc">Table of Contents</a></h2>
+
+<ul>
+
+<li><a href="#Motivation">Motivation</a></li>
+
+<li><a href="#DataTypesAndSimilarityFunctions">Data Types and Similarity Functions</a></li>
+
+<li><a href="#SimilaritySelectionQueries">Similarity Selection Queries</a></li>
+
+<li><a href="#SimilarityJoinQueries">Similarity Join Queries</a></li>
+
+<li><a href="#UsingIndexesToSupportSimilarityQueries">Using Indexes to Support Similarity Queries</a></li>
+</ul></div>
+<div class="section">
+<h2><a name="Motivation_Back_to_TOC"></a><a name="Motivation" id="Motivation">Motivation</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>Similarity queries are widely used in applications where users need to find objects that satisfy a similarity predicate, while exact matching is not sufficient. These queries are especially important for social and Web applications, where errors, abbreviations, and inconsistencies are common. As an example, we may want to find all the movies starring Schwarzenegger, while we don’t know the exact spelling of his last name (despite his popularity in both the movie industry and politics :-)). As another example, we want to find all the Facebook users who have similar friends. To meet this type of needs, AsterixDB supports similarity queries using efficient indexes and algorithms.</p></div>
+<div class="section">
+<h2><a name="Data_Types_and_Similarity_Functions_Back_to_TOC"></a><a name="DataTypesAndSimilarityFunctions" id="DataTypesAndSimilarityFunctions">Data Types and Similarity Functions</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>AsterixDB supports <a class="externalLink" href="http://en.wikipedia.org/wiki/Levenshtein_distance">edit distance</a> (on strings) and <a class="externalLink" href="http://en.wikipedia.org/wiki/Jaccard_index">Jaccard</a> (on sets). For instance, in our <a href="primer.html#ADM:_Modeling_Semistructed_Data_in_AsterixDB">TinySocial</a> example, the <tt>friend-ids</tt> of a Facebook user forms a set of friends, and we can define a similarity between the sets of friends of two users. We can also convert a string to a set of grams of a length “n” (called “n-grams”) and define the Jaccard similarity between the two gram sets of the two strings. Formally, the “n-grams” of a string are its substrings of length “n”. For instance, the 3-grams of the string <tt>schwarzenegger</tt> are <tt>sch</tt>, <tt>chw</tt>, <tt>hwa</tt>, …, <tt>ger</tt>.</p>
+<p>AsterixDB provides <a href="functions.html#Tokenizing_Functions">tokenization functions</a> to convert strings to sets, and the <a href="functions.html#Similarity_Functions">similarity functions</a>.</p></div>
+<div class="section">
+<h2><a name="Similarity_Selection_Queries_Back_to_TOC"></a><a name="SimilaritySelectionQueries" id="SimilaritySelectionQueries">Similarity Selection Queries</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>The following query asks for all the Facebook users whose name is similar to <tt>Suzanna Tilson</tt>, i.e., their edit distance is at most 2.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset('FacebookUsers')
+ let $ed := edit-distance($user.name, "Suzanna Tilson")
+ where $ed <= 2
+ return $user
+</pre></div></div>
+<p>The following query asks for all the Facebook users whose set of friend ids is similar to <tt>[1,5,9,10]</tt>, i.e., their Jaccard similarity is at least 0.6.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset('FacebookUsers')
+ let $sim := similarity-jaccard($user.friend-ids, [1,5,9,10])
+ where $sim >= 0.6f
+ return $user
+</pre></div></div>
+<p>AsterixDB allows a user to use a similarity operator <tt>~=</tt> to express a condition by defining the similarity function and threshold using “set” statements earlier. For instance, the above query can be equivalently written as:</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ set simfunction "jaccard";
+ set simthreshold "0.6f";
+
+ for $user in dataset('FacebookUsers')
+ where $user.friend-ids ~= [1,5,9,10]
+ return $user
+</pre></div></div>
+<p>In this query, we first declare Jaccard as the similarity function using <tt>simfunction</tt> and then specify the threshold <tt>0.6f</tt> using <tt>simthreshold</tt>.</p></div>
+<div class="section">
+<h2><a name="Similarity_Join_Queries_Back_to_TOC"></a><a name="SimilarityJoinQueries" id="SimilarityJoinQueries">Similarity Join Queries</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>AsterixDB supports fuzzy joins between two sets. The following <a href="primer.html#Query_5_-_Fuzzy_Join">query</a> finds, for each Facebook user, all Twitter users with names similar to their name based on the edit distance.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ set simfunction "edit-distance";
+ set simthreshold "3";
+
+ for $fbu in dataset FacebookUsers
+ return {
+ "id": $fbu.id,
+ "name": $fbu.name,
+ "similar-users": for $t in dataset TweetMessages
+ let $tu := $t.user
+ where $tu.name ~= $fbu.name
+ return {
+ "twitter-screenname": $tu.screen-name,
+ "twitter-name": $tu.name
+ }
+ };
+</pre></div></div></div>
+<div class="section">
+<h2><a name="Using_Indexes_to_Support_Similarity_Queries_Back_to_TOC"></a><a name="UsingIndexesToSupportSimilarityQueries" id="UsingIndexesToSupportSimilarityQueries">Using Indexes to Support Similarity Queries</a> <font size="4"><a href="#toc">[Back to TOC]</a></font></h2>
+<p>AsterixDB uses two types of indexes to support similarity queries, namely “ngram index” and “keyword index”.</p>
+<div class="section">
+<h3><a name="NGram_Index"></a>NGram Index</h3>
+<p>An “ngram index” is constructed on a set of strings. We generate n-grams for each string, and build an inverted list for each n-gram that includes the ids of the strings with this gram. A similarity query can be answered efficiently by accessing the inverted lists of the grams in the query and counting the number of occurrences of the string ids on these inverted lists. The similar idea can be used to answer queries with Jaccard similarity. A detailed description of these techniques is available at this <a class="externalLink" href="http://www.ics.uci.edu/~chenli/pub/icde2009-memreducer.pdf">paper</a>.</p>
+<p>For instance, the following DDL statements create an ngram index on the <tt>FacebookUsers.name</tt> attribute using an inverted index of 3-grams.</p>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ create index fbUserIdx on FacebookUsers(name) type ngram(3);
+</pre></div></div>
+<p>The number “3” in “ngram(3)” is the length “n” in the grams. This index can be used to optimize similarity queries on this attribute using <a href="functions.html#edit-distance">edit-distance</a>, <a href="functions.html#edit-distance-check">edit-distance-check</a>, <a href="functions.html#similarity-jaccard">similarity-jaccard</a>, or <a href="functions.html#similarity-jaccard-check">similarity-jaccard-check</a> queries on this attribute where the similarity is defined on sets of 3-grams. This index can also be used to optimize queries with the “<a href="functions.html#contains">contains()</a>” predicate (i.e., substring matching) since it can be also be solved by counting on the inverted lists of the grams in the query string.</p>
+<div class="section">
+<h4><a name="NGram_Index_usage_case_-_edit-distance"></a>NGram Index usage case - <a href="functions.html#edit-distance">edit-distance</a></h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset('FacebookUsers')
+ let $ed := edit-distance($user.name, "Suzanna Tilson")
+ where $ed <= 2
+ return $user
+</pre></div></div></div>
+<div class="section">
+<h4><a name="NGram_Index_usage_case_-_edit-distance-check"></a>NGram Index usage case - <a href="functions.html#edit-distance-check">edit-distance-check</a></h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset('FacebookUsers')
+ let $ed := edit-distance-check($user.name, "Suzanna Tilson", 2)
+ where $ed[0]
+ return $ed[1]
+</pre></div></div></div>
+<div class="section">
+<h4><a name="NGram_Index_usage_case_-_similarity-jaccard"></a>NGram Index usage case - <a href="functions.html#similarity-jaccard">similarity-jaccard</a></h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset('FacebookUsers')
+ let $sim := similarity-jaccard($user.friend-ids, [1,5,9,10])
+ where $sim >= 0.6f
+ return $user
+</pre></div></div></div>
+<div class="section">
+<h4><a name="NGram_Index_usage_case_-_similarity-jaccard-check"></a>NGram Index usage case - <a href="functions.html#similarity-jaccard-check">similarity-jaccard-check</a></h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $user in dataset('FacebookUsers')
+ let $sim := similarity-jaccard-check($user.friend-ids, [1,5,9,10], 0.6f)
+ where $sim[0]
+ return $user
+</pre></div></div></div>
+<div class="section">
+<h4><a name="NGram_Index_usage_case_-_contains"></a>NGram Index usage case - <a href="functions.html#contains">contains()</a></h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ for $i in dataset('FacebookMessages')
+ where contains($i.message, "phone")
+ return {"mid": $i.message-id, "message": $i.message}
+</pre></div></div></div></div>
+<div class="section">
+<h3><a name="Keyword_Index"></a>Keyword Index</h3>
+<p>A “keyword index” is constructed on a set of strings or sets (e.g., OrderedList, UnorderedList). Instead of generating grams as in an ngram index, we generate tokens (e.g., words) and for each token, construct an inverted list that includes the ids of the objects with this token. The following two examples show how to create keyword index on two different types:</p>
+<div class="section">
+<h4><a name="Keyword_Index_on_String_Type"></a>Keyword Index on String Type</h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ drop index FacebookMessages.fbMessageIdx if exists;
+ create index fbMessageIdx on FacebookMessages(message) type keyword;
+
+ for $o in dataset('FacebookMessages')
+ let $jacc := similarity-jaccard-check(word-tokens($o.message), word-tokens("love like verizon"), 0.2f)
+ where $jacc[0]
+ return $o
+</pre></div></div></div>
+<div class="section">
+<h4><a name="Keyword_Index_on_UnorderedList_Type"></a>Keyword Index on UnorderedList Type</h4>
+
+<div class="source">
+<div class="source">
+<pre> use dataverse TinySocial;
+
+ create index fbUserIdx_fids on FacebookUsers(friend-ids) type keyword;
+
+ for $c in dataset('FacebookUsers')
+ let $jacc := similarity-jaccard-check($c.friend-ids, {{3,10}}, 0.5f)
+ where $jacc[0]
+ return $c
+</pre></div></div>
+<p>As shown above, keyword index can be used to optimize queries with token-based similarity predicates, including <a href="functions.html#similarity-jaccard">similarity-jaccard</a> and <a href="functions.html#similarity-jaccard-check">similarity-jaccard-check</a>.</p></div></div></div>
+ </div>
+ </div>
+ </div>
+
+ <hr/>
+
+ <footer>
+ <div class="container-fluid">
+ <div class="row span12">Copyright © 2017
+ <a href="https://www.apache.org/">The Apache Software Foundation</a>.
+ All Rights Reserved.
+
+ </div>
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<div class="row-fluid">Apache AsterixDB, AsterixDB, Apache, the Apache
+ feather logo, and the Apache AsterixDB project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.</div>
+
+
+ </div>
+ </footer>
+ </body>
+</html>