Return-Path: X-Original-To: apmail-accumulo-commits-archive@www.apache.org Delivered-To: apmail-accumulo-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E8CC61085D for ; Thu, 18 Jul 2013 22:47:31 +0000 (UTC) Received: (qmail 81530 invoked by uid 500); 18 Jul 2013 22:47:31 -0000 Delivered-To: apmail-accumulo-commits-archive@accumulo.apache.org Received: (qmail 81503 invoked by uid 500); 18 Jul 2013 22:47:31 -0000 Mailing-List: contact commits-help@accumulo.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@accumulo.apache.org Delivered-To: mailing list commits@accumulo.apache.org Received: (qmail 81496 invoked by uid 500); 18 Jul 2013 22:47:31 -0000 Delivered-To: apmail-incubator-accumulo-commits@incubator.apache.org Received: (qmail 81493 invoked by uid 99); 18 Jul 2013 22:47:31 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 18 Jul 2013 22:47:31 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 18 Jul 2013 22:47:27 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id DCA492388B46 for ; Thu, 18 Jul 2013 22:46:43 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r870045 [9/24] - in /websites/staging/accumulo/trunk/content: ./ 1.4/examples/ 1.4/user_manual/ 1.5/examples/ css/ downloads/ example/ governance/ user_manual_1.3-incubating/ user_manual_1.3-incubating/examples/ Date: Thu, 18 Jul 2013 22:46:39 -0000 To: accumulo-commits@incubator.apache.org From: buildbot@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20130718224643.DCA492388B46@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: websites/staging/accumulo/trunk/content/1.4/user_manual/Table_Design.html ============================================================================== --- websites/staging/accumulo/trunk/content/1.4/user_manual/Table_Design.html (original) +++ websites/staging/accumulo/trunk/content/1.4/user_manual/Table_Design.html Thu Jul 18 22:46:37 2013 @@ -17,7 +17,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - + Apache Accumulo User Manual: Table Design @@ -48,30 +48,31 @@

Project

Community

Development

Documentation

ASF links

    @@ -83,13 +84,12 @@
    - ™ +

    Apache Accumulo User Manual: Table Design

    -

    Next: High-Speed Ingest Up: Apache Accumulo User Manual Version 1.4 Previous: Table Configuration Contents
    -

    +

    Next: High-Speed Ingest Up: Apache Accumulo User Manual Version 1.4 Previous: Table Configuration Contents

    Subsections

    • Basic Table
    • @@ -107,53 +107,53 @@

      We might choose to store this data using the userid as the rowID and the rest of the data in column families:

      -
      Mutation m = new Mutation(new Text(userid));
      -m.put(new Text("age"), age);
      -m.put(new Text("address"), address);
      -m.put(new Text("balance"), account_balance);
      +
      Mutation m = new Mutation(new Text(userid));
      +m.put(new Text("age"), age);
      +m.put(new Text("address"), address);
      +m.put(new Text("balance"), account_balance);
       
      -writer.add(m);
      +writer.add(m);
       

      We could then retrieve any of the columns for a specific userid by specifying the userid as the range of a scanner and fetching specific columns:

      -
      Range r = new Range(userid, userid); // single row
      -Scanner s = conn.createScanner("userdata", auths);
      -s.setRange(r);
      -s.fetchColumnFamily(new Text("age"));
      +
      Range r = new Range(userid, userid); // single row
      +Scanner s = conn.createScanner("userdata", auths);
      +s.setRange(r);
      +s.fetchColumnFamily(new Text("age"));
       
      -for(Entry<Key,Value> entry : s)
      -    System.out.println(entry.getValue().toString());
      +for(Entry<Key,Value> entry : s)
      +    System.out.println(entry.getValue().toString());
       

      RowID Design

      Often it is necessary to transform the rowID in order to have rows ordered in a way that is optimal for anticipated access patterns. A good example of this is reversing the order of components of internet domain names in order to group rows of the same parent domain together:

      -
      com.google.code
      -com.google.labs
      -com.google.mail
      -com.yahoo.mail
      -com.yahoo.research
      +
      com.google.code
      +com.google.labs
      +com.google.mail
      +com.yahoo.mail
      +com.yahoo.research
       

      Some data may result in the creation of very large rows - rows with many columns. In this case the table designer may wish to split up these rows for better load balancing while keeping them sorted together for scanning purposes. This can be done by appending a random substring at the end of the row:

      -
      com.google.code_00
      -com.google.code_01
      -com.google.code_02
      -com.google.labs_00
      -com.google.mail_00
      -com.google.mail_01
      +
      com.google.code_00
      +com.google.code_01
      +com.google.code_02
      +com.google.labs_00
      +com.google.mail_00
      +com.google.mail_01
       

      It could also be done by adding a string representation of some period of time such as date to the week or month:

      -
      com.google.code_201003
      -com.google.code_201004
      -com.google.code_201005
      -com.google.labs_201003
      -com.google.mail_201003
      -com.google.mail_201004
      +
      com.google.code_201003
      +com.google.code_201004
      +com.google.code_201005
      +com.google.labs_201003
      +com.google.mail_201003
      +com.google.mail_201004
       
      @@ -164,27 +164,27 @@

      Note: We store rowIDs in the column qualifier rather than the Value so that we can have more than one rowID associated with a particular term within the index. If we stored this in the Value we would only see one of the rows in which the value appears since Accumulo is configured by default to return the one most recent value associated with a key.

      Lookups can then be done by scanning the Index Table first for occurrences of the desired values in the columns specified, which returns a list of row ID from the main table. These can then be used to retrieve each matching record, in their entirety, or a subset of their columns, from the Main Table.

      To support efficient lookups of multiple rowIDs from the same table, the Accumulo client library provides a BatchScanner. Users specify a set of Ranges to the BatchScanner, which performs the lookups in multiple threads to multiple servers and returns an Iterator over all the rows retrieved. The rows returned are NOT in sorted order, as is the case with the basic Scanner interface.

      -
      // first we scan the index for IDs of rows matching our query
      +
      // first we scan the index for IDs of rows matching our query
       
       Text term = new Text("mySearchTerm");
       
      -HashSet<Text> matchingRows = new HashSet<Text>();
      +HashSet<Text> matchingRows = new HashSet<Text>();
       
       Scanner indexScanner = createScanner("index", auths);
      -indexScanner.setRange(new Range(term, term));
      +indexScanner.setRange(new Range(term, term));
       
      -// we retrieve the matching rowIDs and create a set of ranges
      -for(Entry<Key,Value> entry : indexScanner)
      -    matchingRows.add(new Text(entry.getKey().getColumnQualifier()));
      +// we retrieve the matching rowIDs and create a set of ranges
      +for(Entry<Key,Value> entry : indexScanner)
      +    matchingRows.add(new Text(entry.getKey().getColumnQualifier()));
       
      -// now we pass the set of rowIDs to the batch scanner to retrieve them
      -BatchScanner bscan = conn.createBatchScanner("table", auths, 10);
      +// now we pass the set of rowIDs to the batch scanner to retrieve them
      +BatchScanner bscan = conn.createBatchScanner("table", auths, 10);
       
      -bscan.setRanges(matchingRows);
      -bscan.fetchFamily("attributes");
      +bscan.setRanges(matchingRows);
      +bscan.fetchFamily("attributes");
       
      -for(Entry<Key,Value> entry : scan)
      -    System.out.println(entry.getValue());
      +for(Entry<Key,Value> entry : scan)
      +    System.out.println(entry.getValue());
       
      @@ -195,8 +195,7 @@

      The physical schema for an entity-attribute or graph table is as follows:

      converted table

      For example, to keep track of employees, managers and products the following entity-attribute table could be used. Note that the weights are not always necessary and are set to 0 when not used.

      -

      converted table
      -

      +

      converted table

      To allow efficient updating of edge weights, an aggregating iterator can be configured to add the value of all mutations applied with the same key. These types of tables can easily be created from raw events by simply extracting the entities, attributes, and relationships from individual events and inserting the keys into Accumulo each with a count of 1. The aggregating iterator will take care of maintaining the edge weights.

      Document-Partitioned Indexing

      Using a simple index as described above works well when looking for records that match one of a set of given criteria. When looking for records that match more than one criterion simultaneously, such as when looking for documents that contain all of the words the' andwhite' and `house', there are several issues.

      @@ -206,16 +205,16 @@

      converted table

      Documents or records are mapped into bins by a user-defined ingest application. By storing the BinID as the RowID we ensure that all the information for a particular bin is contained in a single tablet and hosted on a single TabletServer since Accumulo never splits rows across tablets. Storing the Terms as column families serves to enable fast lookups of all the documents within this bin that contain the given term.

      Finally, we perform set intersection operations on the TabletServer via a special iterator called the Intersecting Iterator. Since documents are partitioned into many bins, a search of all documents must search every bin. We can use the BatchScanner to scan all bins in parallel. The Intersecting Iterator should be enabled on a BatchScanner within user query code as follows:

      -
      Text[] terms = {new Text("the"), new Text("white"), new Text("house")};
      +
      Text[] terms = {new Text("the"), new Text("white"), new Text("house")};
       
      -BatchScanner bs = conn.createBatchScanner(table, auths, 20);
      -IteratorSetting iter = new IteratorSetting(20, "ii", IntersectingIterator.class);
      -IntersectingIterator.setColumnFamilies(iter, terms);
      -bs.addScanIterator(iter);
      -bs.setRanges(Collections.singleton(new Range()));
      +BatchScanner bs = conn.createBatchScanner(table, auths, 20);
      +IteratorSetting iter = new IteratorSetting(20, "ii", IntersectingIterator.class);
      +IntersectingIterator.setColumnFamilies(iter, terms);
      +bs.addScanIterator(iter);
      +bs.setRanges(Collections.singleton(new Range()));
       
      -for(Entry<Key,Value> entry : bs) {
      -    System.out.println(" " + entry.getKey().getColumnQualifier());
      +for(Entry<Key,Value> entry : bs) {
      +    System.out.println(" " + entry.getKey().getColumnQualifier());
       }
       
      @@ -228,7 +227,7 @@