KeyFieldHelper.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:9k
源码类别:

网格计算

开发平台:

Java

  1. /**
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.hadoop.mapred.lib;
  19. import java.io.UnsupportedEncodingException;
  20. import java.util.List;
  21. import java.util.ArrayList;
  22. import java.util.StringTokenizer;
  23. import org.apache.hadoop.util.UTF8ByteArrayUtils;
  24. /**
  25.  * This is used in {@link KeyFieldBasedComparator} & 
  26.  * {@link KeyFieldBasedPartitioner}. Defines all the methods
  27.  * for parsing key specifications. The key specification is of the form:
  28.  * -k pos1[,pos2], where pos is of the form f[.c][opts], where f is the number
  29.  *  of the field to use, and c is the number of the first character from the
  30.  *  beginning of the field. Fields and character posns are numbered starting
  31.  *  with 1; a character position of zero in pos2 indicates the field's last
  32.  *  character. If '.c' is omitted from pos1, it defaults to 1 (the beginning
  33.  *  of the field); if omitted from pos2, it defaults to 0 (the end of the
  34.  *  field). opts are ordering options (supported options are 'nr'). 
  35.  */
  36. class KeyFieldHelper {
  37.   
  38.   protected static class KeyDescription {
  39.     int beginFieldIdx = 1;
  40.     int beginChar = 1;
  41.     int endFieldIdx = 0;
  42.     int endChar = 0;
  43.     boolean numeric;
  44.     boolean reverse;
  45.   }
  46.   
  47.   private List<KeyDescription> allKeySpecs = new ArrayList<KeyDescription>();
  48.   private byte[] keyFieldSeparator;
  49.   private boolean keySpecSeen = false;
  50.   
  51.   public void setKeyFieldSeparator(String keyFieldSeparator) {
  52.     try {
  53.       this.keyFieldSeparator =
  54.         keyFieldSeparator.getBytes("UTF-8");
  55.     } catch (UnsupportedEncodingException e) {
  56.       throw new RuntimeException("The current system does not " +
  57.           "support UTF-8 encoding!", e);
  58.     }    
  59.   }
  60.   
  61.   /** Required for backcompatibility with num.key.fields.for.partition in
  62.    * {@link KeyFieldBasedPartitioner} */
  63.   public void setKeyFieldSpec(int start, int end) {
  64.     if (end >= start) {
  65.       KeyDescription k = new KeyDescription();
  66.       k.beginFieldIdx = start;
  67.       k.endFieldIdx = end;
  68.       keySpecSeen = true;
  69.       allKeySpecs.add(k);
  70.     }
  71.   }
  72.   
  73.   public List<KeyDescription> keySpecs() {
  74.     return allKeySpecs;
  75.   }
  76.     
  77.   public int[] getWordLengths(byte []b, int start, int end) {
  78.     //Given a string like "hello how are you", it returns an array
  79.     //like [4 5, 3, 3, 3], where the first element is the number of
  80. //fields
  81.     if (!keySpecSeen) {
  82.       //if there were no key specs, then the whole key is one word
  83.       return new int[] {1};
  84.     }
  85.     int[] lengths = new int[10];
  86.     int currLenLengths = lengths.length;
  87.     int idx = 1;
  88.     int pos;
  89.     while ((pos = UTF8ByteArrayUtils.findBytes(b, start, end, 
  90.         keyFieldSeparator)) != -1) {
  91.       if (++idx == currLenLengths) {
  92.         int[] temp = lengths;
  93.         lengths = new int[(currLenLengths = currLenLengths*2)];
  94.         System.arraycopy(temp, 0, lengths, 0, temp.length);
  95.       }
  96.       lengths[idx - 1] = pos - start;
  97.       start = pos + 1;
  98.     }
  99.     
  100.     if (start != end) {
  101.       lengths[idx] = end - start;
  102.     }
  103.     lengths[0] = idx; //number of words is the first element
  104.     return lengths;
  105.   }
  106.   public int getStartOffset(byte[]b, int start, int end, 
  107.       int []lengthIndices, KeyDescription k) {
  108.     //if -k2.5,2 is the keyspec, the startChar is lengthIndices[1] + 5
  109.     //note that the [0]'th element is the number of fields in the key
  110.     if (lengthIndices[0] >= k.beginFieldIdx) {
  111.       int position = 0;
  112.       for (int i = 1; i < k.beginFieldIdx; i++) {
  113.         position += lengthIndices[i] + keyFieldSeparator.length; 
  114.       }
  115.       if (position + k.beginChar <= (end - start)) {
  116.         return start + position + k.beginChar - 1; 
  117.       }
  118.     }
  119.     return -1;
  120.   }
  121.   public int getEndOffset(byte[]b, int start, int end, 
  122.       int []lengthIndices, KeyDescription k) {
  123.     //if -k2,2.8 is the keyspec, the endChar is lengthIndices[1] + 8
  124.     //note that the [0]'th element is the number of fields in the key
  125.     if (k.endFieldIdx == 0) {
  126.       //there is no end field specified for this keyspec. So the remaining
  127.       //part of the key is considered in its entirety.
  128.       return end; 
  129.     }
  130.     if (lengthIndices[0] >= k.endFieldIdx) {
  131.       int position = 0;
  132.       int i;
  133.       for (i = 1; i < k.endFieldIdx; i++) {
  134.         position += lengthIndices[i] + keyFieldSeparator.length;
  135.       }
  136.       if (k.endChar == 0) { 
  137.         position += lengthIndices[i];
  138.       }
  139.       if (position + k.endChar <= (end - start)) {
  140.         return start + position + k.endChar - 1;
  141.       }
  142.       return end;
  143.     }
  144.     return end;
  145.   }
  146.   public void parseOption(String option) {
  147.     if (option == null || option.equals("")) {
  148.       //we will have only default comparison
  149.       return;
  150.     }
  151.     StringTokenizer args = new StringTokenizer(option);
  152.     KeyDescription global = new KeyDescription();
  153.     while (args.hasMoreTokens()) {
  154.       String arg = args.nextToken();
  155.       if (arg.equals("-n")) {  
  156.         global.numeric = true;
  157.       }
  158.       if (arg.equals("-r")) {
  159.         global.reverse = true;
  160.       }
  161.       if (arg.equals("-nr")) {
  162.         global.numeric = true;
  163.         global.reverse = true;
  164.       }
  165.       if (arg.startsWith("-k")) {
  166.         KeyDescription k = parseKey(arg, args);
  167.         if (k != null) {
  168.           allKeySpecs.add(k);
  169.           keySpecSeen = true;
  170.         }
  171.       }
  172.     }
  173.     for (KeyDescription key : allKeySpecs) {
  174.       if (!(key.reverse | key.numeric)) {
  175.         key.reverse = global.reverse;
  176.         key.numeric = global.numeric;
  177.       }
  178.     }
  179.     if (allKeySpecs.size() == 0) {
  180.       allKeySpecs.add(global);
  181.     }
  182.   }
  183.   
  184.   private KeyDescription parseKey(String arg, StringTokenizer args) {
  185.     //we allow for -k<arg> and -k <arg>
  186.     String keyArgs = null;
  187.     if (arg.length() == 2) {
  188.       if (args.hasMoreTokens()) {
  189.         keyArgs = args.nextToken();
  190.       }
  191.     } else {
  192.       keyArgs = arg.substring(2);
  193.     }
  194.     if (keyArgs == null || keyArgs.length() == 0) {
  195.       return null;
  196.     }
  197.     StringTokenizer st = new StringTokenizer(keyArgs,"nr.,",true);
  198.        
  199.     KeyDescription key = new KeyDescription();
  200.     
  201.     String token;
  202.     //the key is of the form 1[.3][nr][,1.5][nr]
  203.     if (st.hasMoreTokens()) {
  204.       token = st.nextToken();
  205.       //the first token must be a number
  206.       key.beginFieldIdx = Integer.parseInt(token);
  207.     }
  208.     if (st.hasMoreTokens()) {
  209.       token = st.nextToken();
  210.       if (token.equals(".")) {
  211.         token = st.nextToken();
  212.         key.beginChar = Integer.parseInt(token);
  213.         if (st.hasMoreTokens()) {
  214.           token = st.nextToken();
  215.         } else {
  216.           return key;
  217.         }
  218.       } 
  219.       do {
  220.         if (token.equals("n")) {
  221.           key.numeric = true;
  222.         }
  223.         else if (token.equals("r")) {
  224.           key.reverse = true;
  225.         }
  226.         else break;
  227.         if (st.hasMoreTokens()) {
  228.           token = st.nextToken();
  229.         } else {
  230.           return key;
  231.         }
  232.       } while (true);
  233.       if (token.equals(",")) {
  234.         token = st.nextToken();
  235.         //the first token must be a number
  236.         key.endFieldIdx = Integer.parseInt(token);
  237.         if (st.hasMoreTokens()) {
  238.           token = st.nextToken();
  239.           if (token.equals(".")) {
  240.             token = st.nextToken();
  241.             key.endChar = Integer.parseInt(token);
  242.             if (st.hasMoreTokens()) {
  243.               token = st.nextToken();
  244.             } else {
  245.               return key;
  246.             }
  247.           }
  248.           do {
  249.             if (token.equals("n")) {
  250.               key.numeric = true;
  251.             }
  252.             else if (token.equals("r")) {
  253.               key.reverse = true;
  254.             }
  255.             else { 
  256.               throw new IllegalArgumentException("Invalid -k argument. " +
  257.                "Must be of the form -k pos1,[pos2], where pos is of the form " +
  258.                "f[.c]nr");
  259.             }
  260.             if (st.hasMoreTokens()) {
  261.               token = st.nextToken();
  262.             } else {
  263.               break;
  264.             }
  265.           } while (true);
  266.         }
  267.         return key;
  268.       }
  269.       throw new IllegalArgumentException("Invalid -k argument. " +
  270.           "Must be of the form -k pos1,[pos2], where pos is of the form " +
  271.           "f[.c]nr");
  272.     }
  273.     return key;
  274.   }
  275.   private void printKey(KeyDescription key) {
  276.     System.out.println("key.beginFieldIdx: " + key.beginFieldIdx);
  277.     System.out.println("key.beginChar: " + key.beginChar);
  278.     System.out.println("key.endFieldIdx: " + key.endFieldIdx);
  279.     System.out.println("key.endChar: " + key.endChar);
  280.     System.out.println("key.numeric: " + key.numeric);
  281.     System.out.println("key.reverse: " + key.reverse);
  282.     System.out.println("parseKey over");
  283.   }  
  284. }