乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      HBase權(quán)威指南中文版第三章翻譯

       閑來(lái)看看 2013-08-14

      第三章 客戶端API: 基礎(chǔ)篇(第二部分)

      Get操作

      Get方法是用來(lái)從HBase中取出相應(yīng)的數(shù)據(jù)??梢愿鶕?jù)它們一次取出的條數(shù)分成兩類:?jiǎn)螚lGet、多條Get。

      單條Get

      可以使用如下的接口從HBase出取出特定的數(shù)據(jù)出來(lái):

      Result get(Get
      get) throws IOException

      Put類類似,Get類提供了一個(gè)get方法,在調(diào)用該方法時(shí),您同樣需要提供一個(gè)Get實(shí)例,該實(shí)例必須指定一個(gè)rowkey,它有如下的兩種創(chuàng)造函數(shù):

      Get(byte[] row)

      Get(byte[] row,
      RowLock rowLock)

      一個(gè)get方法從來(lái)取一個(gè)特殊的行,但可以取出這一行中的多個(gè)列。Get類的構(gòu)造函數(shù)必須指定一個(gè)row,第二個(gè)構(gòu)造函數(shù)還可以指定一個(gè)RowLock,允許您使用一個(gè)自己定義的行鎖。與Put類相似,Get類也指供了大量的方法從來(lái)設(shè)置您所要找的行,或者精確到一個(gè)具體的Cell

      Get
      addFamily(byte[] family)

      Get
      addColumn(byte[] family, byte[] qualifier)

      Get
      setTimeRange(long minStamp, long maxStamp) throws IOException

      Get
      setTimeStamp(long timestamp)

      Get
      setMaxVersions()

      Get
      setMaxVersions(int maxVersions) throws IOException

      addFamily將查詢的行限制到特定的Column Family上。它可以被調(diào)用多次來(lái)添加多個(gè)Column Family。對(duì)于addColumn方法也是一樣的。您可以給Get實(shí)例添加更多的限制條件,比如時(shí)間戳范圍、版本數(shù)目等。

      一次get操作允許取回一行記錄的多個(gè)版本,在不設(shè)置取回的版本數(shù)目下,默認(rèn)返回最近的一個(gè)版本。如果您有所懷疑,可以通過(guò)接口getMaxVersions()查看。對(duì)于無(wú)參的setMaxVersions()調(diào)用,會(huì)將版本數(shù)設(shè)為Integer.MAX_VALUE,從而取回這一行對(duì)應(yīng)的所有版本。Get類也提供了其它的一些函數(shù)調(diào)用,在表3-4中列出了他們的用法。

      3-4 Get類部分方法列舉

      Method

      Description

      getRow()

      Returns the row key as
      specified when creating the Get instance.

      getRowLock()

      Returns the row RowLock
      instance for the current Get instance.

      getLockId()

      Returns the optional lock ID
      handed into the constructor using the rowlock
      parameter. Will be -1L if not
      set.

      getTimeRange()

      Retrieves the associated
      timestamp or time range of the Get instance. Note that
      there is no getTimeStamp()
      since the API converts a value assigned with set
      TimeStamp() into a TimeRange
      instance internally, setting the minimum and
      maximum values to the given
      timestamp.

      setFilter()/getFilter()

      Special filter instances can
      be used to select certain columns or cells, based on a wide
      variety of conditions. You can
      get and set them with these methods.

      setCacheBlocks()/

      getCacheBlocks()

      Each HBase region server has a
      block cache that efficiently retains recently accessed
      data for subsequent reads of
      contiguous information. In some events it is better to
      not engage the cache to avoid
      too much churn when doing completely random gets.
      These methods give you control
      over this feature.

      numFamilies()

      Convenience method to retrieve
      the size of the family map, containing the families
      added using the addFamily() or
      addColumn() calls.

      hasFamilies()

      Another helper to check if a
      family
      or columnhas been
      added to the current
      instance of the Get class.

      familySet()/

      getFamilyMap()

      These methods give you access
      to the column families and specific columns, as added
      by the addFamily() and/or
      addColumn() calls. The family map is a map where
      the key is the family name and
      the value a list of added column qualifiers for this
      particular family. The
      familySet() returns the Set of all stored families, i.e., a
      set containing only the family
      names.

      3-4中表出的getter方法,只能取出對(duì)Get設(shè)置過(guò)的值。因此,他們很少被用到。

      在前面提到過(guò),HBase提供了一個(gè)名為Bytes的幫助類,該類提供了很多的靜態(tài)方法實(shí)現(xiàn)Java中的類型與byte數(shù)組的轉(zhuǎn)換。它也提供了反向的轉(zhuǎn)換,即從byte數(shù)組,解析出相應(yīng)的Java類型。下面給出了Bytes類的一些方法:

      static String
      toString(byte[] b)

      static boolean
      toBoolean(byte[] b)

      static long
      toLong(byte[] bytes)

      static float
      toFloat(byte[] bytes)

      static int
      toInt(byte[] bytes)

      示例3-8演示了如何使用它們:

      示例3-8 HBase中獲取數(shù)據(jù)

      Configuration conf
      = HBaseConfiguration.create();

      HTable table = new
      HTable(conf, “testtable”);

      Get get = new
      Get(Bytes.toBytes(“row1″));

      get.addColumn(Bytes.toBytes(“colfam1″),
      Bytes.toBytes(“qual1″));

      Result result =
      table.get(get);

      byte[] val = result.getValue(Bytes.toBytes(“colfam1″),

      Bytes.toBytes(“qual1″));

      System.out.println(“Value:
      ” + Bytes.toString(val));

      首先創(chuàng)建一個(gè)HBase的配置文件,初始化一個(gè)HTable的實(shí)例。創(chuàng)建一個(gè)指定向row1Get實(shí)例,向Get中添加一個(gè)colfam1的列,和一個(gè)qual1qualifier。然后從HBase中取出這一行的對(duì)應(yīng)的數(shù)據(jù),最后將數(shù)據(jù)轉(zhuǎn)化成相應(yīng)的格式并打印出來(lái)。如果您運(yùn)行上述的示例代碼,應(yīng)該打印出:

      Value: val1

      Result

      如果調(diào)用get()函數(shù)取出數(shù)據(jù),您將會(huì)得到一個(gè)Result對(duì)象,它持有所有相符的Cell。當(dāng)您使用特定的行、特定的查詢條件(如column family,
      column qualifier, timestamp
      等)從HBase服務(wù)器上取出一個(gè)Result對(duì)象后,您可以利用它來(lái)取出所有您想要的結(jié)果。

      就像前面示例3-8給出的一樣,您可以得到更多的維度信息。比如,要求服務(wù)器返回指定column family的所有列,這樣您在客戶端側(cè)就可以通過(guò)get方法取得所有的列信息。下面給出了Result類提供的一些方法:

      byte[]
      getValue(byte[] family, byte[] qualifier)

      byte[] value()

      byte[] getRow()

      int size()

      boolean isEmpty()

      KeyValue[] raw()

      List<KeyValue>
      list()

      getValue方法從HBase中一個(gè)特定的Cell中取出數(shù)據(jù)。您可以不設(shè)定時(shí)間戳、版本數(shù),從而獲得最近的一個(gè)版本數(shù)據(jù)。由于服務(wù)器上同一行的數(shù)據(jù)按照版本由新到舊的順序排度,因此,總是服務(wù)器查到的第一次記錄就是最新的一個(gè)版本。

      前面已經(jīng)介紹過(guò)getRow():它返回rowkey,即在創(chuàng)建Get實(shí)例時(shí)指定的rowkey。size()方法可以得到服務(wù)器返回的KeyValue實(shí)例的數(shù)目。isEmpty可以判斷KeyValue實(shí)例的數(shù)目是否為空。

      通過(guò)row方法,可以得到當(dāng)前Result實(shí)例后存儲(chǔ)的一組KeyValue實(shí)例數(shù)組,list方法可以將KeyValue數(shù)組對(duì)象轉(zhuǎn)化成一個(gè)List對(duì)象,從而可以簡(jiǎn)單地通過(guò)迭代器進(jìn)行訪問(wèn)。

      raw()方法返回的數(shù)組已經(jīng)經(jīng)過(guò)了排序,排序的維度是Column family
      > Column qualifier > timetamp > type

      還有一組面向Column的方法:

      List<KeyValue>
      getColumn(byte[] family, byte[] qualifier)

      KeyValue
      getColumnLatest(byte[] family, byte[] qualifier)

      boolean containsColumn(byte[]
      family, byte[] qualifier)

      要得到一個(gè)列對(duì)應(yīng)的一組KeyValue,您必須先調(diào)用setMaxVersions設(shè)定要取得多個(gè)版本,否則只能得到一個(gè)KeyValuegetCOlumnLatest返回這個(gè)列對(duì)應(yīng)的最新的一個(gè)Cell。getValue()方法并不返回一個(gè)raw字節(jié)數(shù)組,而是返回KeyValue對(duì)象。containsColumn可以非常便捷的查看返回的Cell中是否指定的Column列。

      所有的方法中的qualifier字段都可以設(shè)置為null,這樣可以匹配qualifier為空的列。Qualifier為空意味著列沒(méi)有label。當(dāng)查看一個(gè)表中的數(shù)據(jù)時(shí),比如使用shell命令,您必須了解表中有哪些列。很少會(huì)使用到空的qualifier,在這些情況下,意味著只有一個(gè)column,這時(shí)column family便起到了column的作用。

      還有另一個(gè)方法集,可以對(duì)請(qǐng)求得到的數(shù)據(jù)進(jìn)行訪問(wèn)。它們是面向map的訪問(wèn)方式:

      NavigableMap<byte[],
      NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap()

      NavigableMap<byte[],
      avigableMap<byte[], byte[]>> getNoVersionMap()

      NavigableMap<byte[],
      byte[]> getFamilyMap(byte[] family)

      getMap是更通用的調(diào)用方式,以Java Map的方法,返回整個(gè)result集合,可以通過(guò)迭代的方式遍歷所有的值。getNoVersionMap()方法只返回最新的一個(gè)版本的數(shù)據(jù)。第三個(gè)getMap方法返回指定family下的所有版本的value值。

      使用哪組接口訪問(wèn)Result對(duì)象取決于你的習(xí)慣; 數(shù)據(jù)已經(jīng)通過(guò)網(wǎng)絡(luò)從服務(wù)器轉(zhuǎn)輸?shù)搅丝蛻舳?,并不存在效率的差別。

      批量Get

      put方法中,可以一次插入一組Put對(duì)象。類似地,get操作也允許一次從服務(wù)器上取一組Get對(duì)象。批量Get是一種高效地訪問(wèn)HBase的方法,但同樣不能保證多條數(shù)據(jù)之間的順序。

      從前面的圖3-1可以看出來(lái),請(qǐng)求不只會(huì)發(fā)送到一臺(tái)服務(wù)器上,但從客戶端看來(lái),仿佛只有一條請(qǐng)求發(fā)出。

      批量GetAPI定義如下:

      Result[]
      get(List<Get> gets) throws IOException

      跟前面的批量put一樣,您需要先創(chuàng)建一個(gè)隊(duì)列來(lái)存儲(chǔ)Get實(shí)例,這些實(shí)例保存要請(qǐng)求的條件,而服務(wù)器端返回查詢出來(lái)的Result結(jié)果。示例3-9給出了如何使用兩種不同的方式取數(shù)據(jù)。

      示例3-9 批量從HBase中取數(shù)據(jù)

      byte[] cf1 =
      Bytes.toBytes(“colfam1″);

      byte[] qf1 =
      Bytes.toBytes(“qual1″);

      byte[] qf2 =
      Bytes.toBytes(“qual2″);

      byte[] row1 =
      Bytes.toBytes(“row1″);

      byte[] row2 =
      Bytes.toBytes(“row2″);

      List<Get>
      gets = new ArrayList<Get>();

      Get get1 = new
      Get(row1);

      get1.addColumn(cf1,
      qf1);

      gets.add(get1);

      Get get2 = new
      Get(row2);

      get2.addColumn(cf1,
      qf1);

      gets.add(get2);

      Get get3 = new
      Get(row2);

      get3.addColumn(cf1,
      qf2);

      gets.add(get3);

      Result[] results =
      table.get(gets);

      System.out.println(“First
      iteration…”);

      for (Result result
      : results) {

      String
      row = Bytes.toString(result.getRow());

      System.out.print(“Row:
      ” + row + ” “);

      byte[]
      val = null;

      if
      (result.containsColumn(cf1, qf1)) {

      val
      = result.getValue(cf1, qf1);

      System.out.println(“Value:
      ” + Bytes.toString(val));

      }

      if
      (result.containsColumn(cf1, qf2)) {

      val
      = result.getValue(cf1, qf2);

      System.out.println(“Value:
      ” + Bytes.toString(val));

      }

      }

      System.out.println(“Second
      iteration…”);

      for (Result result
      : results) {

      for
      (KeyValue kv : result.raw()) {

      System.out.println(“Row:
      ” + Bytes.toString(kv.getRow()) +

      ” Value:
      ” + Bytes.toString(kv.getValue()));

      }

      }

      示例中首先定義了一組byte數(shù)據(jù),用來(lái)存放column family的名字、column qualifier的名字、row的名字。然后創(chuàng)建一個(gè)List保存所有的Get請(qǐng)求對(duì)象。最后調(diào)用HTableget方法,從服務(wù)器上批量讀取數(shù)據(jù)。在第一個(gè)迭代遍歷的過(guò)程中,只打印出colfam1、qual1對(duì)應(yīng)的列和colfam1、qual2對(duì)應(yīng)的值。第二個(gè)迭代遍歷的過(guò)程中打印出所有取到的值。

      假設(shè)您在運(yùn)行了示例3-4之后,運(yùn)行示例3-9,那么您將得到如下的輸出:

      First iteration…

      Row: row1 Value:
      val1

      Row: row2 Value:
      val2

      Row: row2 Value:
      val3

      Second
      iteration…

      Row: row1 Value:
      val1

      Row: row2 Value:
      val2

      Row: row2 Value:
      val3

      兩次迭代過(guò)程會(huì)打印相同的值。示例告訴您,如何訪問(wèn)批量get的結(jié)果。您現(xiàn)在還不了解的便是出錯(cuò)如何通知到您。這和前面講到的put是有所不同的,get操作要么取出與Get實(shí)例大小相等的結(jié)果,要么拋出一個(gè)異常。示例3-10給出一個(gè)例子:

      示例3-10 讀出一個(gè)錯(cuò)誤的column family

      List<Get>
      gets = new ArrayList<Get>();

      Get get1 = new
      Get(row1);

      get1.addColumn(cf1,
      qf1);

      gets.add(get1);

      Get get2 = new
      Get(row2);

      get2.addColumn(cf1,
      qf1);

      gets.add(get2);

      Get get3 = new
      Get(row2);

      get3.addColumn(cf1,
      qf2);

      gets.add(get3);

      Get get4 = new Get(row2);

      get4.addColumn(Bytes.toBytes(“BOGUS”),
      qf2);

      gets.add(get4);

      Result[] results =
      table.get(gets);

      System.out.println(“Result count: ” + results.length);

      上述代碼首先將Get實(shí)例插入到一個(gè)List中,其中一個(gè)Get實(shí)例指定了一個(gè)虛假的column family值。因此,一個(gè)異常將會(huì)被拋出,最后的打印記錄永遠(yuǎn)不會(huì)輸出來(lái)。執(zhí)行上述代碼,將會(huì)得到一個(gè)如下的異常:

      org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException:

      Failed 1 action:
      NoSuchColumnFamilyException: 1 time,

      servers with
      issues: 10.0.0.57:51640,

      batch()是一種更有控制力的API,它能處理部分出錯(cuò)的情況。在后文的批量操作部分將會(huì)介紹到這個(gè)API。

      相關(guān)解析數(shù)據(jù)方法

      很多的函數(shù)都可以取出服務(wù)器返回的結(jié)果數(shù)據(jù),先介紹下面這個(gè):

      boolean exists(Get
      get) throws IOException

      該函數(shù)需先創(chuàng)建一個(gè)Get對(duì)象,它并不從服務(wù)器上取Get對(duì)象對(duì)應(yīng)的結(jié)果數(shù)據(jù),而是要求服務(wù)器返回是否存在對(duì)應(yīng)記錄的標(biāo)志。

      Resion Server使用相同的處理流程來(lái)處理exists請(qǐng)求,包括加載文件塊來(lái)確定是否含對(duì)指定的columnrowkey。但數(shù)據(jù)并不經(jīng)過(guò)網(wǎng)絡(luò)傳輸。因此,對(duì)于一些大的column列,該方法還是很有用的。

      有時(shí),您或許想請(qǐng)一個(gè)確定的row,或者在它前面的row,并取出相應(yīng)的數(shù)據(jù)。此時(shí),您可以調(diào)用下面的接口:

      Result
      getRowOrBefore(byte[] row, byte[] family) throws IOException

      您必須指定相應(yīng)的row和一個(gè)column family,當(dāng)然column family不是必需的。結(jié)果返回您要找的row,或者是位于它前面的一個(gè)。如果一個(gè)也沒(méi)有找到,該方法返回null。示例3-11給出如何查詢前面put示例中插入的數(shù)據(jù)。

      示例3-11 使用一個(gè)專門的讀取方法

      Result result1 =
      table.getRowOrBefore(Bytes.toBytes(“row1″),

      Bytes.toBytes(“colfam1″));

      System.out.println(“Found:
      ” + Bytes.toString(result1.getRow()));

      Result result2 =
      table.getRowOrBefore(Bytes.toBytes(“row99″),

      Bytes.toBytes(“colfam1″));

      System.out.println(“Found:
      ” + Bytes.toString(result2.getRow()));

      for (KeyValue kv :
      result2.raw()) {

      System.out.println(”
      Col: ” + Bytes.toString(kv.getFamily()) +

      “/”
      + Bytes.toString(kv.getQualifier()) +

      “,
      Value: ” + Bytes.toString(kv.getValue()));

      }

      Result result3 =
      table.getRowOrBefore(Bytes.toBytes(“abc”),

      Bytes.toBytes(“colfam1″));

      System.out.println(“Found:
      ” + result3);

      示例中首先去尋找一個(gè)存在的row,并打印出找到的記錄。然后試圖去尋找一個(gè)不存在的row,打印出了表的最后一行記錄。最后,去尋找一個(gè)排在row1前的“abc”,將會(huì)打印出來(lái)null

      上述代碼的輸出如下:

      Found: row1

      Found: row2

      Col:
      colfam1/qual1, Value: val2

      Col:
      colfam1/qual2, Value: val3

      Found: null

      第一次調(diào)用直接請(qǐng)求一個(gè)已經(jīng)存在的記錄會(huì)返回這條記錄。第二次調(diào)用請(qǐng)求了一個(gè)很大的row值“row99”,它顯然排在row2的后面,因此調(diào)用getRowOrBefore會(huì)得到row2的值。最后請(qǐng)求“abc”,按字母序,abc排在row1的前面。因此,調(diào)用getRowOrBefore會(huì)得到null。在循環(huán)打印第二次請(qǐng)求“row99”的結(jié)果時(shí),可以發(fā)現(xiàn)row2對(duì)應(yīng)的所有列均被取出,并按照qualifier的順序進(jìn)行排列。

      Delete操作

      您現(xiàn)在已經(jīng)可以創(chuàng)建、讀取和更新HBase表中的記錄了,下面將介紹刪除操作。您大概也可以猜出來(lái),HTable對(duì)象一定提供了一個(gè)類叫做Delete。

      單條刪除

      delete()方法有一種單條刪除接口形式,如下:

      void delete(Delete
      delete) throws IOException

      get、put調(diào)用相似,該調(diào)用首先要?jiǎng)?chuàng)建一個(gè)Delete實(shí)例,并將要?jiǎng)h除的詳細(xì)信息添加到這個(gè)實(shí)例中。Detele的創(chuàng)建函數(shù)如下:

      Delete(byte[] row)

      Delete(byte[] row,
      long timestamp, RowLock rowLock)

      您必須提供要?jiǎng)h除rowrowkey,或者額外提供一個(gè)RowLock。這和前面的put、get單條操作都是完全相同的。有時(shí),您或許不想將rowkey對(duì)應(yīng)的整行刪除,您只想刪除某個(gè)版本的記錄,或者是某個(gè)column family、某個(gè)column
      qualifier
      下的記錄,您可以調(diào)用如下的方法:

      Delete
      deleteFamily(byte[] family)

      Delete
      deleteFamily(byte[] family, long timestamp)

      Delete
      deleteColumns(byte[] family, byte[] qualifier)

      Delete
      deleteColumns(byte[] family, byte[] qualifier, long timestamp)

      Delete
      deleteColumn(byte[] family, byte[] qualifier)

      void
      setTimestamp(long timestamp)

      第一個(gè)函數(shù)可以刪除指定的column family下的記錄,當(dāng)然也包括了它對(duì)應(yīng)的所有的column。第二個(gè)函數(shù)刪除指定的column family對(duì)應(yīng)的timestamp以前的所有版本的數(shù)據(jù)。第三個(gè)函數(shù)刪除指定的column family和指定的column
      qualifier
      的記錄。第四個(gè)函數(shù)在第三個(gè)函數(shù)的基礎(chǔ)上,刪除timestamp以前的所有版本。最后一個(gè)函數(shù),可以對(duì)Delete對(duì)象設(shè)定時(shí)間戳,刪除其以前的版本記錄。第五個(gè)方法僅刪除最后一個(gè)版本的數(shù)據(jù)。表3-5以表格的形式給出了幾個(gè)delete函數(shù)及其用法,更加直觀。

      3-5 delete()調(diào)用

      Method

      Description

      Delete with timestamp

      none

      Entire row, i.e., all columns,
      all versions.

      All versions of all columns in
      all column families, whose
      timestamp is equal to or older than the given timestamp.

      deleteColumn()

      Only the latest version of the
      given
      column; older versions are
      kept.

      Only exactly the specified
      version of the given column,
      with the matching timestamp. If nonexistent, nothing is deleted.

      deleteColumns()

      All versions of the given
      column.

      Versions equal to or older
      than the given timestamp of
      the given column.

      deleteFamily()

      All columns (including all
      versions) of the given family.

      Versions equal to or older
      than the given timestamp of
      all columns of the given family.

      3-6列出了Delete類提供的另外一些方法。

      3-6
      Delete
      類的另外幾個(gè)方法

      Method

      Description

      getRow()

      Returns the row key as
      specified when creating the Delete instance.

      getRowLock()

      Returns the row RowLock
      instance for the current Delete instance.

      getLockId()

      Returns the optional lock ID handed
      into the constructor using the rowLock parameter. Will be
      -1L if not set.

      getTimeStamp()

      Retrieves the associated
      timestamp of the Delete instance.

      isEmpty()

      Checks if the family map
      contains any entries. In other words, if you specified any column family,
      or column qualifier, that
      should be deleted.

      getFamilyMap()

      Gives you access to the added
      column families and specific columns, as added by the deleteFamily() and/or
      deleteColumn()/deleteColumns() calls. The returned map uses the
      family name as the key, and
      the value it points to is a list of added column qualifiers for this
      particular family.

      示例3-12給出了如何客戶端如何調(diào)用一個(gè)單條刪除方法。

      示例3-12 HBase數(shù)據(jù)刪除

      Delete delete =
      new Delete(Bytes.toBytes(“row1″));

      delete.setTimestamp(1);

      delete.deleteColumn(Bytes.toBytes(“colfam1″),
      Bytes.toBytes(“qual1″), 1);

      delete.deleteColumns(Bytes.toBytes(“colfam2″),
      Bytes.toBytes(“qual1″));

      delete.deleteColumns(Bytes.toBytes(“colfam2″),
      Bytes.toBytes(“qual3″), 15);

      delete.deleteFamily(Bytes.toBytes(“colfam3″));

      delete.deleteFamily(Bytes.toBytes(“colfam3″),
      3);

      table.delete(delete);

      table.close();

      首先創(chuàng)建一個(gè)指向row1Delete對(duì)象,為該Delete對(duì)象設(shè)定timestamp值為1。然后調(diào)用delete刪除Column的接口,并指定一個(gè)版本。然后刪除另一列colfam2qual1下的所有版本,然后刪除該列colfam2:qual2下指定版本以前的所有版本。接著刪除colfam3下整個(gè)family,包含所有版本。再刪除colfam3下版本3以前的所有版本。最后執(zhí)行刪除操作。

      在上面的示例給出了您可以使用的delete操作的所有函數(shù)形式。您可以依次執(zhí)行并觀察它們的輸出。

      Delete對(duì)象設(shè)定timestamp,使用deleteColumn接口只能刪除特定的cell,使用deleteColumns接口可以刪除精確的timestamp匹配得到比這個(gè)時(shí)間戳舊的所有版本(包括相等的)。

      批量刪除

      批量刪除操作同批量插入很相似,您需要?jiǎng)?chuàng)建一個(gè)Delete實(shí)例的列表,然后通過(guò)delete方法刪除它們。

      void
      delete(List<Delete> deletes) throws IOException

      示例3-13給出了一個(gè)批量刪除的例子。當(dāng)您運(yùn)行這個(gè)例子時(shí),將會(huì)打印刪除前后delete的狀態(tài)。打印原生的KeyValue對(duì)象,可以使用KeyValue.toString()方法(前面介紹過(guò)該方法)。

      同前面介紹的批量操作相類,您不能保證服務(wù)器端收到的Delete實(shí)例的順序。API可能會(huì)打亂它們的順序,進(jìn)行重排。如果您很在意一組Delete實(shí)例執(zhí)行的前后順序,您必須把它們分成小的隊(duì)列,按照您所期望的順序依次執(zhí)行它們。最壞的情況便是,您一條一條的進(jìn)行刪除操作。

      示例3-13 批量刪除

      List<Delete>
      deletes = new ArrayList<Delete>();

      Delete delete1 =
      new Delete(Bytes.toBytes(“row1″));

      delete1.setTimestamp(4);

      deletes.add(delete1);

      Delete delete2 =
      new Delete(Bytes.toBytes(“row2″));

      delete2.deleteColumn(Bytes.toBytes(“colfam1″),
      Bytes.toBytes(“qual1″));

      delete2.deleteColumns(Bytes.toBytes(“colfam2″),
      Bytes.toBytes(“qual3″), 5);

      deletes.add(delete2);

      Delete delete3 =
      new Delete(Bytes.toBytes(“row3″));

      delete3.deleteFamily(Bytes.toBytes(“colfam1″));

      delete3.deleteFamily(Bytes.toBytes(“colfam2″),
      3);

      deletes.add(delete3);

      table.delete(deletes);

      table.close();

      首先創(chuàng)建了一個(gè)Delete對(duì)象的列表,然后為它們?cè)O(shè)置timestamp,刪除一個(gè)指定的版本。然后刪除colfam2:qual3下等于或小于版本5的所有數(shù)據(jù)。delete3刪除row3下的整個(gè)colfam1,刪除colfam2下等于或舊于版本3的所有記錄。最后通過(guò)HTable執(zhí)行批量刪除。

      下面給出了HBase刪除數(shù)據(jù)前后對(duì)應(yīng)的數(shù)據(jù):

      Before delete
      call…

      KV:
      row1/colfam1:qual1/2/Put/vlen=4, Value: val2

      KV:
      row1/colfam1:qual1/1/Put/vlen=4, Value: val1

      KV:
      row1/colfam1:qual2/4/Put/vlen=4, Value: val4

      KV: row1/colfam1:qual2/3/Put/vlen=4,
      Value: val3

      KV:
      row1/colfam1:qual3/6/Put/vlen=4, Value: val6

      KV:
      row1/colfam1:qual3/5/Put/vlen=4, Value: val5

      KV:
      row1/colfam2:qual1/2/Put/vlen=4, Value: val2

      KV:
      row1/colfam2:qual1/1/Put/vlen=4, Value: val1

      KV: row1/colfam2:qual2/4/Put/vlen=4,
      Value: val4

      KV:
      row1/colfam2:qual2/3/Put/vlen=4, Value: val3

      KV:
      row1/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV:
      row1/colfam2:qual3/5/Put/vlen=4, Value: val5

      KV:
      row2/colfam1:qual1/2/Put/vlen=4, Value: val2

      KV:
      row2/colfam1:qual1/1/Put/vlen=4, Value: val1

      KV:
      row2/colfam1:qual2/4/Put/vlen=4, Value: val4

      KV:
      row2/colfam1:qual2/3/Put/vlen=4, Value: val3

      KV:
      row2/colfam1:qual3/6/Put/vlen=4, Value: val6

      KV:
      row2/colfam1:qual3/5/Put/vlen=4, Value: val5

      KV:
      row2/colfam2:qual1/2/Put/vlen=4, Value: val2

      KV:
      row2/colfam2:qual1/1/Put/vlen=4, Value: val1

      KV:
      row2/colfam2:qual2/4/Put/vlen=4, Value: val4

      KV:
      row2/colfam2:qual2/3/Put/vlen=4, Value: val3

      KV:
      row2/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV:
      row2/colfam2:qual3/5/Put/vlen=4, Value: val5

      KV:
      row3/colfam1:qual1/2/Put/vlen=4, Value: val2

      KV:
      row3/colfam1:qual1/1/Put/vlen=4, Value: val1

      KV:
      row3/colfam1:qual2/4/Put/vlen=4, Value: val4

      KV:
      row3/colfam1:qual2/3/Put/vlen=4, Value: val3

      KV:
      row3/colfam1:qual3/6/Put/vlen=4, Value: val6

      KV: row3/colfam1:qual3/5/Put/vlen=4,
      Value: val5

      KV:
      row3/colfam2:qual1/2/Put/vlen=4, Value: val2

      KV:
      row3/colfam2:qual1/1/Put/vlen=4, Value: val1

      KV:
      row3/colfam2:qual2/4/Put/vlen=4, Value: val4

      KV:
      row3/colfam2:qual2/3/Put/vlen=4, Value: val3

      KV: row3/colfam2:qual3/6/Put/vlen=4,
      Value: val6

      KV:
      row3/colfam2:qual3/5/Put/vlen=4, Value: val5

      After delete
      call…

      KV:
      row1/colfam1:qual3/6/Put/vlen=4, Value: val6

      KV:
      row1/colfam1:qual3/5/Put/vlen=4, Value: val5

      KV:
      row1/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV: row1/colfam2:qual3/5/Put/vlen=4,
      Value: val5

      KV:
      row2/colfam1:qual1/1/Put/vlen=4, Value: val1

      KV:
      row2/colfam1:qual2/4/Put/vlen=4, Value: val4

      KV:
      row2/colfam1:qual2/3/Put/vlen=4, Value: val3

      KV:
      row2/colfam1:qual3/6/Put/vlen=4, Value: val6

      KV: row2/colfam1:qual3/5/Put/vlen=4,
      Value: val5

      KV:
      row2/colfam2:qual1/2/Put/vlen=4, Value: val2

      KV:
      row2/colfam2:qual1/1/Put/vlen=4, Value: val1

      KV:
      row2/colfam2:qual2/4/Put/vlen=4, Value: val4

      KV:
      row2/colfam2:qual2/3/Put/vlen=4, Value: val3

      KV:
      row2/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV:
      row3/colfam2:qual2/4/Put/vlen=4, Value: val4

      KV:
      row3/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV:
      row3/colfam2:qual3/5/Put/vlen=4, Value: val5

      可以執(zhí)行如下的代碼,打印出上述的結(jié)果:

      System.out.println(“KV:
      ” + kv.toString() +

      “,
      Value: ” + Bytes.toString(kv.getValue()))

      現(xiàn)在您應(yīng)該很熟悉Bytes類的使用方法,特別是對(duì)KeyValue結(jié)構(gòu)的處理。KeyValue.toString()方法只會(huì)打印出key部分的值,而并不會(huì)打印出對(duì)應(yīng)的value值(因?yàn)?/SPAN>value值可以非常大)。在示例中,由于表中的value值,是我們自己插入的,我們知道它的長(zhǎng)度,因此可以放心用終端打印出來(lái),在您的應(yīng)用中,也可以用類似的辦法進(jìn)行調(diào)試。

      如果從本書(shū)所配的代碼庫(kù)整體來(lái)看,您便會(huì)明白數(shù)據(jù)是如何入庫(kù)和讀取的。下面將討論批量刪除操作的出錯(cuò)處理。delete方法接收的一組Delete對(duì)象,當(dāng)服務(wù)器端刪除出錯(cuò)時(shí),將刪除出錯(cuò)的Delete對(duì)象依然通過(guò)該參數(shù)返回到客戶端。

      示例3-14 HBase上刪除錯(cuò)誤的記錄

      Delete delete4 =
      new Delete(Bytes.toBytes(“row2″));

      delete4.deleteColumn(Bytes.toBytes(“BOGUS”),
      Bytes.toBytes(“qual1″));

      deletes.add(delete4);

      try {

      table.delete(deletes);

      } catch (Exception
      e) {

      System.err.println(“Error:
      ” + e);

      }

      table.close();

      System.out.println(“Deletes
      length: ” + deletes.size());

      for (Delete delete
      : deletes) {

      System.out.println(delete);

      }

      首先創(chuàng)建一個(gè)指向一個(gè)不存在列的Delete對(duì)象,然后在刪除該對(duì)象時(shí),會(huì)得到一個(gè)異常。查看返回的List的大小,然后打印出刪除出錯(cuò)的Delete對(duì)象。

      示例3-14在示例3-13的基礎(chǔ)上添加了一個(gè)出錯(cuò)的delete對(duì)象,可以得到類似3-13的輸出結(jié)果,但會(huì)有幾條增加的輸出:

      Before delete
      call…

      KV:
      row1/colfam1:qual1/2/Put/vlen=4, Value: val2

      KV:
      row1/colfam1:qual1/1/Put/vlen=4, Value: val1

      KV:
      row3/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV:
      row3/colfam2:qual3/5/Put/vlen=4, Value: val5

      Error:
      org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException:

      Failed
      1 action: NoSuchColumnFamilyException: 1 time,

      servers
      with issues: 10.0.0.43:59057,

      Deletes length: 1

      row=row2, ts=9223372036854775807,
      families={(family=BOGUS, keyvalues= \

      (row2/BOGUS:qual1/9223372036854775807/Delete/vlen=0)}

      After delete
      call…

      KV:
      row1/colfam1:qual3/6/Put/vlen=4, Value: val6

      KV:
      row1/colfam1:qual3/5/Put/vlen=4, Value: val5

      KV: row3/colfam2:qual3/6/Put/vlen=4,
      Value: val6

      KV:
      row3/colfam2:qual3/5/Put/vlen=4, Value: val5

      正如所期望的一樣,隊(duì)列會(huì)返回一個(gè)Delete實(shí)例,并指向“BOGUS”對(duì)應(yīng)的column family。我們使用toString()方法打印出出錯(cuò)的一行。Family名字是出錯(cuò)的根本原因。您在應(yīng)用程序中也可以使用這種方法來(lái)判斷刪除操作出錯(cuò)的行,一般情況下,刪除出錯(cuò)都是因?yàn)檫@個(gè)原因。

      最后,出錯(cuò)拋出的異常和前面例子中的異常類似,RetriesExhaustedWithDetailsException已經(jīng)是第二次看到了。它打印出了出錯(cuò)時(shí)重做的次數(shù)。后面的章節(jié)將會(huì)講到如何監(jiān)控monitor server,因此,異常中返回的服務(wù)器IP是非常有用的。

      原子性的compare-and-delete

      在前面的“原子性的compare-and-set”一節(jié)中,講到了如使用原子性的比較、插入數(shù)據(jù)到HBase中的表中。對(duì)于刪除操作也給出了一個(gè)類似的方法,以原子的形式,在服務(wù)器端進(jìn)行比較,滿足條件后進(jìn)行刪除:

      boolean
      checkAndDelete(byte[] row, byte[] family, byte[] qualifier,

      byte[]
      value, Delete delete) throws IOException

      上述方法需要指定rowkey、column family、qualifiervalue來(lái)檢查,如果有滿足條件的值,則執(zhí)行delete。如果檢查失敗,則delete不執(zhí)行。當(dāng)delete成功執(zhí)行后返回true。示例3-15給出了一個(gè)使用的例子:

      示例3-15 原子例的compare-and-set刪除操作

      Delete delete1 =
      new Delete(Bytes.toBytes(“row1″));

      delete1.deleteColumns(Bytes.toBytes(“colfam1″),
      Bytes.toBytes(“qual3″));

      boolean res1 =
      table.checkAndDelete(Bytes.toBytes(“row1″),

      Bytes.toBytes(“colfam2″),
      Bytes.toBytes(“qual3″), null, delete1);

      System.out.println(“Delete
      successful: ” + res1);

      Delete delete2 =
      new Delete(Bytes.toBytes(“row1″));

      delete2.deleteColumns(Bytes.toBytes(“colfam2″),
      Bytes.toBytes(“qual3″));

      table.delete(delete2);

      boolean res2 = table.checkAndDelete(Bytes.toBytes(“row1″),

      Bytes.toBytes(“colfam2″),
      Bytes.toBytes(“qual3″), null, delete1);

      System.out.println(“Delete
      successful: ” + res2);

      Delete delete3 =
      new Delete(Bytes.toBytes(“row2″));

      delete3.deleteFamily(Bytes.toBytes(“colfam1″));

      try{

      boolean
      res4 = table.checkAndDelete(Bytes.toBytes(“row1″),

      Bytes.toBytes(“colfam1″),
      Bytes.toBytes(“qual1″),

      Bytes.toBytes(“val1″),
      delete3);

      System.out.println(“Delete
      successful: ” + res4);

      } catch (Exception
      e) {

      System.err.println(“Error:
      ” + e);

      }

      首先創(chuàng)建了一個(gè)Delete實(shí)例,指向row1對(duì)應(yīng)的colfam1:qual3列。然后檢查是否存在rowkeyrow1,具含有colfam2:qual3列,不存該列,則執(zhí)行Delete實(shí)例,并打印出執(zhí)行的結(jié)果。由于檢查的列是存在的,運(yùn)行會(huì)打印出來(lái)“Delete
      successful: false
      ”。手工要檢查的列后,再執(zhí)行checkAndDelete,成功執(zhí)行,打印出“Delete successful:
      true
      ”。最后,嘗試checkdeleterowkey不一致,則會(huì)拋出一個(gè)異常。整個(gè)代碼執(zhí)行的輸出如下:

      Before delete
      call…

      KV:
      row1/colfam1:qual1/2/Put/vlen=4, Value: val2

      KV:
      row1/colfam1:qual1/1/Put/vlen=4, Value: val1

      KV:
      row1/colfam1:qual2/4/Put/vlen=4, Value: val4

      KV:
      row1/colfam1:qual2/3/Put/vlen=4, Value: val3

      KV: row1/colfam1:qual3/6/Put/vlen=4,
      Value: val6

      KV:
      row1/colfam1:qual3/5/Put/vlen=4, Value: val5

      KV:
      row1/colfam2:qual1/2/Put/vlen=4, Value: val2

      KV:
      row1/colfam2:qual1/1/Put/vlen=4, Value: val1

      KV:
      row1/colfam2:qual2/4/Put/vlen=4, Value: val4

      KV: row1/colfam2:qual2/3/Put/vlen=4,
      Value: val3

      KV:
      row1/colfam2:qual3/6/Put/vlen=4, Value: val6

      KV:
      row1/colfam2:qual3/5/Put/vlen=4, Value: val5

      Delete successful:
      false

      Delete successful:
      true

      After delete
      call…

      KV:
      row1/colfam1:qual1/2/Put/vlen=4, Value: val2

      KV: row1/colfam1:qual1/1/Put/vlen=4,
      Value: val1

      KV:
      row1/colfam1:qual2/4/Put/vlen=4, Value: val4

      KV:
      row1/colfam1:qual2/3/Put/vlen=4, Value: val3

      KV:
      row1/colfam2:qual1/2/Put/vlen=4, Value: val2

      KV:
      row1/colfam2:qual1/1/Put/vlen=4, Value: val1

      KV: row1/colfam2:qual2/4/Put/vlen=4,
      Value: val4

      KV:
      row1/colfam2:qual2/3/Put/vlen=4, Value: val3

      Error:
      org.apache.hadoop.hbase.DoNotRetryIOException:

      org.apache.hadoop.hbase.DoNotRetryIOException:

      Action’s getRow
      must match the passed row

      使用null作為check操作的value,值不存在則check成功。由于在執(zhí)行前check的值已經(jīng)存在了,所以第一次check返回了false,delete操作未執(zhí)行。而后手工刪除了要check的值,再執(zhí)行checkAndDelete時(shí),check成功,delete操作被成功執(zhí)行。

      這和前面介紹的put操作對(duì)應(yīng)的CAS調(diào)用是一樣的,您只能在同一行上執(zhí)行check-and-modify操作,若行不一致,將會(huì)拋出一個(gè)異常。當(dāng)然,check-and-modify操作允許checkmodify操作的是同一行中兩個(gè)不同的column family。

      示例沒(méi)有說(shuō)明check-and-modify操作有多么重要,在分布式系統(tǒng)中,在不加鎖、不損失性能的情況下保證操作的可靠性和原子性是很難的。因此,客戶端使用了一個(gè)排它鎖占有整個(gè)行。若客戶端在加鎖的階段出現(xiàn)了故障了,集群必須要保證被加鎖的行要重新unlock。在check-and-modify操作時(shí),會(huì)出現(xiàn)額外的RPC調(diào)用,因此,肯定會(huì)比單獨(dú)的服務(wù)器端操作慢一些。


      上一部分:HBase權(quán)威指南(中文版)——第三章(第一部分)

      下一部分:HBase權(quán)威指南(中文版)——第三章(第三部分)

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多