Hadoop 自定義Writable NullpointerException
阿新 • • 發佈:2019-01-30
Hadoop環境:Hadoop2.4
在定義Hadoop的Writable時候,有時需要使用到陣列,而不是簡單的字串或者單個的數值。比如下面的程式碼:
可以看到其無參建構函式裡面含有一個初始化的操作,這個初始化的操作限定了其矩陣distance的維度(程式碼中設定為6),但是一般這個值由外部設定才比較合適,但是在讀取的時候,也就是readFields的時候是從這個無參建構函式進入的,這裡沒有辦法設定引數,沒有辦法在外面初始化這個矩陣的大小,但是不設定又不行,有沒有什麼辦法呢?在Mahout的一些程式碼中可以看到類似的程式碼,比如VectorWritable,從VectorWritable可以找到解決這個問題的答案。先看看vectorWritable的一段程式碼:package test; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import org.apache.hadoop.io.WritableComparable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyData implements WritableComparable<MyData>,Cloneable { private Logger log = LoggerFactory.getLogger(MyData.class); private float[] distance; public MyData(){// 空指標異常 set(new float[6]); // 註釋掉此行程式碼,在readFields會有空指標異常 } public MyData(float[] distance) { set(distance); } public void set(float[] distance) { this.distance=distance; } @Override public void readFields(DataInput arg0) throws IOException { for(int i=0;i<distance.length;i++){ distance[i]=arg0.readFloat(); } } @Override public void write(DataOutput arg0) throws IOException { for(int i=0;i<distance.length;i++){ arg0.writeFloat(distance[i]); } } @Override public int compareTo(MyData o) {// 當前值小於o則返回負數 float[] oDistance =o.distance; int cmp=0; for(int i=0;i<oDistance.length;i++){ if(Math.abs(this.distance[i]-oDistance[i])<0.0000000001){ continue; // 比較下一個 } if(this.distance[i]<oDistance[i]){ return -1; }else{ return 1; } } return cmp; } @Override public int hashCode(){ int hashCode =0; for(int i=0;i<distance.length;i++){ hashCode=+Float.floatToIntBits(distance[i]); } return hashCode; } public float[] getDistance() { return distance; } public void setDistance(float[] distance) { this.distance = distance; } }
通過這段程式碼可以知道,不一定要通過外部傳入,其實可以從in中讀取即可。具體如何做呢?定義一個數組distance的大小變數,比如為num,然後把num在write中寫入,然後在readFields中先讀出,然後再初始化陣列distance,這樣就不會有剛才的問題了。具體程式碼如下:@Override public void readFields(DataInput in) throws IOException { int flags = in.readByte(); int size = Varint.readUnsignedVarInt(in); readFields(in, (byte) flags, size); }
package test; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import org.apache.hadoop.io.WritableComparable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyData implements WritableComparable<MyData>,Cloneable { private Logger log = LoggerFactory.getLogger(MyData.class); private float[] distance; private int num; public MyData(){// 此處不再有空指標異常 // set(new float[6]); // 註釋掉此行程式碼,在readFields不會有空指標異常 } public MyData(float[] distance) { this.num=distance.length; set(distance); } public void set(float[] distance) { this.distance=distance; } @Override public void readFields(DataInput arg0) throws IOException { num = arg0.readInt(); distance = new float[num]; for(int i=0;i<distance.length;i++){ distance[i]=arg0.readFloat(); } } @Override public void write(DataOutput arg0) throws IOException { arg0.writeInt(num); for(int i=0;i<distance.length;i++){ arg0.writeFloat(distance[i]); } } @Override public int compareTo(MyData o) {// 當前值小於o則返回負數 float[] oDistance =o.distance; int cmp=0; for(int i=0;i<oDistance.length;i++){ if(Math.abs(this.distance[i]-oDistance[i])<0.0000000001){ continue; // 比較下一個 } if(this.distance[i]<oDistance[i]){ return -1; }else{ return 1; } } return cmp; } @Override public int hashCode(){ int hashCode =0; for(int i=0;i<distance.length;i++){ hashCode=+Float.floatToIntBits(distance[i]); } return hashCode; } public float[] getDistance() { return distance; } public void setDistance(float[] distance) { this.distance = distance; } }
通過上面的改進,就不用擔心 空指標的問題了。
分享,成長,快樂