All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sequoiadb.hadoop.io.BSONWritableComparator Maven / Gradle / Ivy

/*
 * Copyright 2010-2013 10gen Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sequoiadb.hadoop.io;


import java.nio.ByteBuffer;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.apache.commons.logging.*;
import org.apache.hadoop.io.*;
import org.bson.BSONObject;
import org.bson.BasicBSONObject;
import org.bson.types.BSONTimestamp;
import org.bson.types.BasicBSONList;
import org.bson.types.Binary;
import org.bson.types.Code;
import org.bson.types.CodeWScope;
import org.bson.types.MaxKey;
import org.bson.types.MinKey;
import org.bson.types.ObjectId;
import org.bson.types.Symbol;

/**
 * 
 * 
 * @className:BSONWritableComparator
 *
 * @author: gaoshengjie
 *
 * @createtime:2013年12月13日 上午11:05:29
 *
 * @changetime:TODO
 *
 * @version 1.0.0 
 *
 */
public class BSONWritableComparator extends WritableComparator {	
    private static final Log log = LogFactory.getLog( BSONWritableComparator.class );
    private static final Map, Integer> types;
    static {
        Map, Integer> aType = new HashMap, Integer>();
        aType.put(MinKey.class, 1);
        aType.put(null, 2);
        aType.put(Integer.class, 3);
        aType.put(Double.class, 3);
        aType.put(Float.class, 3);
        aType.put(String.class, 4);
        aType.put(Symbol.class, 4); 
        aType.put(BasicBSONObject.class, 5);
        aType.put(BasicBSONList.class, 6);
        aType.put(Binary.class, 7);
        aType.put(byte[].class, 7);
        aType.put(ObjectId.class, 8);
        aType.put(Boolean.class, 9);
        aType.put(Date.class, 10);
        aType.put(BSONTimestamp.class, 10);
        aType.put(Pattern.class, 11);
        aType.put(Code.class, 13);
        aType.put(CodeWScope.class, 13);
        aType.put(MaxKey.class, 12);
        types = aType;

    }

	

    public BSONWritableComparator(){
        super( BSONWritable.class, true );
    }

    protected BSONWritableComparator( Class keyClass ){
        super( keyClass, true );
    }

    protected BSONWritableComparator( Class keyClass, boolean createInstances ){
        super( keyClass, createInstances );
    }


    public int compare( WritableComparable a, WritableComparable b ){
        if ( a instanceof BSONWritable && b instanceof BSONWritable ){
            return compare(((BSONWritable)a).getBson(), ((BSONWritable)b).getBson());
        }else{
            return -1;
        }
    }

    public int compare( byte[] b1, int s1, int l1, byte[] b2, int s2, int l2 ){
        return super.compare( b1, s1, l1, b2, s2, l2 );
    }

    public int compare( Object a, Object b ){
        return compare(((BSONWritable)a).getBson(), ((BSONWritable)b).getBson());
        //return super.compare( a, b );
    }
    
    private Iterator> getIterator(BSONObject obj) {
        
        if (obj instanceof BasicBSONObject) {
            return ((BasicBSONObject) obj).entrySet().iterator();
        } else {
            throw new IllegalArgumentException("only support BasicBSONObject");
        }
    }

    
    private  int compare(BSONObject obj1, BSONObject obj2) {

        Iterator> iter1 = getIterator(obj1);
        Iterator> iter2 = getIterator(obj2);
        
        while (iter1.hasNext()) {
            // If the key, values up to now are the same, but 2 has more elements left
            if (!iter2.hasNext()) {
                return -1;
            }
            
            Entry entry1 = iter1.next();
            Entry entry2 = iter2.next();
            
            // Different keys at this index
            int diff = entry1.getKey().compareTo(entry2.getKey());
            if (diff != 0) {
                return diff;
            }

            // Comparing the values (could be null values)
            Object one = entry1.getValue();
            Object two = entry2.getValue();

            // For now MinKey won't be used here, so if the value is not 
            // null, then the comparison order must be greater than null's
            if (one == null && two == null) {
                continue;
            } 
            if (one == null && two != null) {
                return -1;
            }
            if (one != null && two == null) {
                return 1;
            } else {

                // Whether they're the same type
                Integer oneValue = types.get(one.getClass());
                Integer twoValue = types.get(two.getClass());
                diff = oneValue.compareTo(twoValue);
                if (diff != 0) {
                    return diff;
                }

                diff = compareValues(one, two);

                // If not the same, return immediately, else keep checking
                if (diff != 0) {
                    return diff;
                }
            }

        }
        
        if (iter2.hasNext()) {
            return 1;
        }
        
        return 0;
    }
    
    private int compareValues(Object one, Object two) {
        int diff = 0;
        if (one instanceof Number) {
            // Need to be comparing all numeric values to one another, 
            // so cast all of them to Double
            diff = (Double.valueOf(one.toString())).
                    compareTo(Double.valueOf(two.toString()));
        } else if (one instanceof String) {
            diff = ((String) one).compareTo((String) two);
        } else if (one instanceof BSONObject) {
            // BasicBSONObject and BasicBSONList both covered in this cast
            diff = compare((BSONObject) one, (BSONObject)two);
        } else if (one instanceof Binary) {
            ByteBuffer buff1 = ByteBuffer.wrap(((Binary) one).getData());
            ByteBuffer buff2 = ByteBuffer.wrap(((Binary) two).getData());
            diff = buff1.compareTo(buff2);
        } else if (one instanceof byte[]) {
            ByteBuffer buff1 = ByteBuffer.wrap((byte[]) one);
            ByteBuffer buff2 = ByteBuffer.wrap((byte[]) two);
            diff = buff1.compareTo(buff2);
        } else if (one instanceof ObjectId) {
            diff = ((ObjectId) one).compareTo((ObjectId) two);
        } else if (one instanceof Boolean) {
            diff = ((Boolean) one).compareTo((Boolean) two);
        } else if (one instanceof Date) {
            diff = ((Date) one).compareTo((Date) two);
        } else if (one instanceof BSONTimestamp) {
            diff =compareBSONTimestamp((BSONTimestamp) one ,(BSONTimestamp) two);
        }
        
        // MinKey, MaxKey, Pattern, Code, and CodeWScope aren't cast options

        return diff;
    }
    
    private int compareBSONTimestamp(BSONTimestamp left,BSONTimestamp right){
    	if(left.getTime()!=right.getTime()){
    		return left.getTime()-right.getTime();
    	}else{
    		return left.getInc()-right.getInc();
    	}
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy