<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          HBase 工具 | HBase SDK 3.0.0發(fā)布,讓HBase的使用變得更簡捷

          共 45013字,需瀏覽 91分鐘

           ·

          2022-12-17 18:52

          1. hbase-sdk 介紹

          hbase-sdk是基于 hbase-client 和 hbase-thrift 的原生 API 封裝的一款輕量級的 HBase 客戶端操作工具包。針對 HBase 各版本 API(1.x~2.x)之間的差異,在其上制定了一層統(tǒng)一的接口。在兼容原有功能的同時,還為其擴(kuò)展了 ORM 的特性。除此之外,hbase-sdk還提供了以類 SQL 的方式讀寫 HBase 表中數(shù)據(jù)的能力。

          2. hbase-sdk 的優(yōu)勢

          hbase-sdk 基于 HBase 的原生 API,封裝了對 HBase 表及其數(shù)據(jù)的 DML 和 DDL 操作。同時,利用其 ORM 的特性,可實現(xiàn) Java 數(shù)據(jù)實體類與 HBase 表進(jìn)行綁定,與原生的 API 相比,其優(yōu)勢總結(jié)如下:
          1. 基于原生 API 中 Get/Put/Scan 等功能,重新定義了統(tǒng)一的操作接口,屏蔽了底層 HBase 各版本原生 API 間的差異,在面對集群跨大版本升級時,業(yè)務(wù)伙伴只需對應(yīng)升級自己項目中的hbase-client的版本即可。
          2. 簡化了原生 API 較為復(fù)雜的調(diào)用方式,在 ORM 特性的加持之下,沒有 HBase API 調(diào)用經(jīng)驗的開發(fā)伙伴,也能快速完成對 HBase 表數(shù)據(jù)的讀寫業(yè)務(wù)。
          3. 對 HBase 的原生 thrift api 進(jìn)行了池化封裝,類似于 Jedis-pool,增強(qiáng)了 thrift api 生產(chǎn)環(huán)境中使用的穩(wěn)定性。
          4. 使用 spring-boot-starter-hbase 可快速與 SpringBoot 無縫集成。
          5. 提供了類 SQL 的方式——HQL 來讀寫 HBase 表中的數(shù)據(jù),進(jìn)一步簡化了原生 API 的使用方式。
          API 文檔地址: https://weixiaotome.gitee.io/hbase-sdk/如果你也覺得這個項目不錯,可以幫忙點個star 。

          3. 現(xiàn)有特性與未來規(guī)劃

          • [d] 定義了統(tǒng)一的接口規(guī)范,消除了 HBase 不同版本原生 API 之間的差異
          • [d] ORM 特性,以注解方式快速實現(xiàn)表、列簇、字段模型與 java 實體類進(jìn)行綁定
          • [d] 對 HBase 的原生 thrift API 進(jìn)行池化封裝,提供了 HBaseThriftPool 的功能
          • [d] HQL,以類 SQL 的形式讀寫 HBase 表中的數(shù)據(jù)
          • [d] 利用 spring-boot-starter-hbase 可無縫與 SpringBoot 集成
          • [ ] HBatis,類似于 myBatis,提供配置文件管理 HQL 的功能(規(guī)劃中)
          • [ ] 客戶端熔斷,提供客戶端 API 級別的主備集群切換,保障請求 HBase 接口服務(wù)的高可用(規(guī)劃中)
          • [ ] thrift 連接池中連接數(shù)的動態(tài)擴(kuò)所容能力(規(guī)劃中)

          4. 倉庫地址

          https://github.com/CCweixiao/hbase-sdk
          https://gitee.com/weixiaotome/hbase-sdk
          兩邊倉庫地址是同步更新的,歡迎各位大佬在Github上幫忙點個star 。

          5. 編譯指南

          克隆項目到本地,導(dǎo)入到 IDEA 中,首次加載項目,會從遠(yuǎn)程倉庫拉取項目所需的依賴,還請耐心等待。
          cd hbase-sdk
          mvn clean install -Phbase-1.2 # hbase-client:1.2.x
          mvn clean install -Phbase-1.4 # hbase-client:1.4.x
          mvn clean install -Phbase-2.2 # hbase-client:2.x.x

          或者跳過findbugs、checkstyle等檢查

          mvn clean package -Dmaven.test.skip=true -Dfindbugs.skip -Dcheckstyle.skip -Dmaven.javadoc.skip -Phbase-1.2

          mvn clean package -Dmaven.test.skip=true -Dfindbugs.skip -Dcheckstyle.skip -Dmaven.javadoc.skip -Phbase-1.4

          mvn clean package -Dmaven.test.skip=true -Dfindbugs.skip -Dcheckstyle.skip -Dmaven.javadoc.skip -Phbase-2.2
          hbase-sdk的hbase-sdk-adapter模塊下的各個子模塊中已引入了具體的 hbase-shaded-client 的依賴,如有需要可以自行擴(kuò)展你想使用的 hbase-client 的版本。

          6. 項目結(jié)構(gòu)概覽

          project
          項目結(jié)構(gòu)說明,主要介紹核心模塊的作用。
          ├── hbase-sdk-adapter                       # HBase各版本不兼容API的adapter
          │   ├── hbase-sdk-adapter-common
          │   ├── hbase-sdk-adapter_1.2
          │   ├── hbase-sdk-adapter_1.4
          │   ├── hbase-sdk-adapter_2.2
          │   └── pom.xml
          ├── hbase-sdk-common                            # 通用工具或接口
          ├── hbase-sdk-dsl                                   # HBase SQL
          ├── hbase-sdk-examples
          │   ├── hbase-sdk-example
          │   └── spring-boot-starter-hbase-example
          ├── hbase-sdk-template                      # hbase操作模版類API
          ├── hbase-sdk-thrift                            # HBase thrift API
          └── spring-boot-starter-hbase           # spring-boot-starter-hbase
          hbase-sdk的 UML 類圖概覽:
          api-uml

          7. 快速開始

          hbase-sdk 的各個版本完成開發(fā)測試之后,都會發(fā)布到 maven 中央倉庫之中,只是最新版本的代碼有一定的延遲。如果你想在第一時間體驗新的功能,可以選擇克隆 Gitee 或 Github 倉庫中的源碼,在本地編譯并運(yùn)行測試用例。
          hbase-sdk 如果你想在本地進(jìn)行開發(fā),請確保已經(jīng)安裝了 Java8 和 maven3.6+。同時建議在本地部署一個可連通的 HBase 開發(fā)環(huán)境。建議使用 docker 來快速搭建一個 HBase 的單機(jī)環(huán)境,可以參考博客:https://blog.csdn.net/feinifi/article/details/121174846
          hbase-sdk 開發(fā)所用的工具為 IDEA,所以也極力推薦導(dǎo)入項目到 IDEA 中。

          7.1 在普通項目中引入 hbase-sdk-template 依賴

          創(chuàng)建一個基礎(chǔ)的 Maven 工程,HBase SDK 已適配了 hbase-client 的 1.2/1.4/2.x 版本 API。
          如果你的 HBase 版本是 1.2.x,可以使用如下依賴。
          <dependency>
              <groupId>com.github.CCweixiao</groupId>
              <artifactId>hbase-sdk-template_1.2</artifactId>
              <version>3.0.0</version>
          </dependency>
          如果你的 HBase 版本是 1.4.x,可以使用如下依賴。
          <dependency>
              <groupId>com.github.CCweixiao</groupId>
              <artifactId>hbase-sdk-template_1.4</artifactId>
              <version>3.0.0</version>
          </dependency>
          如果你的 HBase 版本是 2.x.x,可以使用如下依賴。
          <dependency>
              <groupId>com.github.CCweixiao</groupId>
              <artifactId>hbase-sdk-template_2.2</artifactId>
              <version>3.0.0</version>
          </dependency>
          hbase-sdk目前最新的版本是3.0.0。你可以在 maven 中央倉庫中搜索 CCweixiao 來獲取 hbase-sdk 相關(guān) jar 包的最新版本。https://mvnrepository.com/artifact/com.github.CCweixiao
          或者在 git 倉庫中查看最新的 release 版本。
          當(dāng)然,如果你想重新編譯,擴(kuò)展你需要的功能,也可以選擇下載源碼,修改項目根 pom.xml 文件中的hbase.version,按照編譯指南中的編譯命令來操作。

          7.2 在SpringBoot 項目中引入 spring-boot-starter-hbase 依賴

          創(chuàng)建一個基于Maven的 spring boot 工程,在項目 pom.xml 中加入 spring-boot-starter-hbase 的依賴。
          如果你的 HBase 版本是 1.2.x,可以使用如下依賴。
          <dependency>
              <groupId>com.github.CCweixiao</groupId>
              <artifactId>spring-boot-starter-hbase_1.2</artifactId>
              <version>3.0.0</version>
          </dependency>
          如果你的 HBase 版本是 1.4.x,可以使用如下依賴。
          <dependency>
              <groupId>com.github.CCweixiao</groupId>
              <artifactId>spring-boot-starter-hbase_1.4</artifactId>
              <version>3.0.0</version>
          </dependency>
          如果你的 HBase 版本是 2.x.x,可以使用如下依賴。
          <dependency>
              <groupId>com.github.CCweixiao</groupId>
              <artifactId>spring-boot-starter-hbase_2.2</artifactId>
              <version>3.0.0</version>
          </dependency>

          7.3 引入hbase-client的依賴

          hbase-sdk沒有把 hbase-client 的依賴打到自己的包中,所以,除了引入hbase-sdk的相關(guān)依賴之外,你還需要引入hbase-client的依賴,hbase-client的版本目前支持1.2.x、1.4.x2.x.x,請按需引入。(建議使用 hbase-shaded-client)。
          <dependency>
              <groupId>org.apache.hbase</groupId>
              <artifactId>hbase-shaded-client</artifactId>
              <version>1.2.0</version>
          </dependency>
          or
          <dependency>
              <groupId>org.apache.hbase</groupId>
              <artifactId>hbase-shaded-client</artifactId>
              <version>1.4.3</version>
          </dependency>
          or
          <dependency>
              <groupId>org.apache.hbase</groupId>
              <artifactId>hbase-shaded-client</artifactId>
              <version>2.2.6</version>
          </dependency>

          7.5 HBase 連接配置

          普通 Java 項目
          普通認(rèn)證
          // 普通認(rèn)證
          Properties properties = new Properties();
          properties.setProperty("hbase.zookeeper.quorum""myhbase");
          properties.setProperty("hbase.zookeeper.property.clientPort""2181");
          // 請按需引入一些額外所需的客戶端配置
          properties.put("hbase.client.retries.number""3");
          Kerberos 認(rèn)證
          Properties properties = new Properties();
          properties.put("hbase.zookeeper.quorum""zk_host1,zk_host1,zk_host1");
          properties.put("hbase.zookeeper.property.clientPort""2181");
          properties.put("hbase.security.authentication""kerberos");
          properties.put("kerberos.principal""[email protected]");
          properties.put("keytab.file""/etc/hbase/conf/hbase.keytab");
          properties.put("hbase.regionserver.kerberos.principal""hbase/[email protected]");
          properties.put("hbase.master.kerberos.principal""hbase/[email protected]");
          // 指定kdc服務(wù)相關(guān)的配置方式有如下兩種:
          // 方式一:指定krb5.conf路徑
          properties.put("java.security.krb5.conf""/etc/krb5.conf");
          // 方式二:指定java.security.krb5.realm和java.security.krb5.kdc
          properties.put("java.security.krb5.realm""HADOOP.LEO.COM");
          properties.put("java.security.krb5.kdc""你自己的kdc服務(wù)地址");
          // 一些額外的客戶端參數(shù)
          properties.put("hbase.client.retries.number""3");

          IHBaseAdminTemplate adminTemplate adminTemplate = new HBaseAdminTemplateImpl.Builder().properties(properties).build();
          System.out.println(adminTemplate.listTableNames());
          Spring Boot 項目
          普通認(rèn)證
          application.yaml
          spring:
            datasource:
              hbase:
                zk-host-list: zk_host1,zk_host2,zk_host3
                zk-client-port: 2181 # (可選,默認(rèn)2181)
                dfs-root-dir: /hbase # (可選,默認(rèn)/hbase)
                zk-node-parent: /hbase  # (可選,默認(rèn)/hbase)
                security-auth-way: simple # (可選,默認(rèn)simple)
                client-properties: hbase.client.retries.number=3;key1=value2
          server:
            port: 8088
          Kerberos 認(rèn)證
          spring:
            datasource:
              hbase:
                zk-host-list: zk_host1,zk_host2,zk_host3
                zk-client-port: 2181 # (可選,默認(rèn)2181)
                dfs-root-dir: /hbase # (可選,默認(rèn)/hbase)
                zk-node-parent: /hbase  # (可選,默認(rèn)/hbase)
                security-auth-way: kerberos
                kerberos-principal: [email protected]
                keytab-file-path: /etc/hbase/conf/hbase.keytab
                rs-kerberos-principal: hbase/[email protected]
                master-kerberos-principal: hbase/[email protected]
                # krb5-conf-path和krb5-realm、krb5-kdc-server-addr任選一種配置KDC的方式
                krb5-conf-path: /etc/krb5.conf
                krb5-realm:
                krb5-kdc-server-addr:
                client-properties: hbase.client.retries.number=3;key1=value2
          server:
            port: 8088

          7.6 創(chuàng)建 API 操作模版實現(xiàn)類

          普通項目
          // 表中數(shù)據(jù)讀寫API的操作模版類
          IHBaseTableTemplate tableTemplate = new HBaseAdminTemplateImpl.Builder()
                          .properties(properties).build();
          // 管理員API操作模版類
          IHBaseAdminTemplate adminTemplate = new HBaseAdminTemplateImpl.Builder()
                          .properties(properties).build();
          // HQL API操作模版類
          IHBaseSqlTemplate sqlTemplate = new HBaseSqlTemplateImpl.Builder()
                          .properties(properties).build()
          SpringBoot 項目
          @Autowired依賴注IHBaseTableTemplate、IHBaseAdminTemplate、IHBaseSqlTemplate
          @Service
          public class UserService {
              @Autowired
              private IHBaseTableTemplate tableTemplate;
              @Autowired
              private IHBaseAdminTemplate adminTemplate;
              @Autowired
              private IHBaseSqlTemplate sqlTemplate;
          }

          8. 集群管理

          HBaseAdminTemplate 封裝了 HBaseAdmin 的常用操作,比如 namespace 的管理、表的管理、以及快照管理等等,后續(xù)這些 API 將會更加完善。
          admin-api

          8.1 創(chuàng)建 namespace

          @Test
          public void createNameSpace() {
              NamespaceDesc namespaceDesc = new NamespaceDesc();
              namespaceDesc.setNamespaceName("test_nn");
              namespaceDesc.addNamespaceProp("createdBy""leojie");
              adminTemplate.createNamespaceAsync(namespaceDesc);
          }

          8.2 創(chuàng)建表

          @Test
          public void testCreateTable() {
              ColumnFamilyDesc f1 = new ColumnFamilyDesc.Builder()
                      .familyName("f1")
                      .build();
              ColumnFamilyDesc f2 = new ColumnFamilyDesc.Builder()
                      .familyName("f2")
                      .timeToLive(3600)
                      .versions(3)
                      .build();
              HTableDesc tableDesc = new HTableDesc.Builder()
                      .defaultTableDesc("test_nn:test_table")
                      .maxFileSize(51400000L)
                      .addTableProp("hbase.hstore.block.storage.policy""HOT")
                      .addColumnFamilyDesc(f1)
                      .addColumnFamilyDesc(f2)
                      .build();
              adminTemplate.createTable(tableDesc);
          }

          8.3 更多操作

          可以參考相關(guān) API 文檔或hbase-template模塊下的測試用例

          9. 數(shù)據(jù)讀寫

          類似于 Hibernate,你也可以使用 hbase-sdk 框架所提供的 ORM 特性,來實現(xiàn)對 HBase 表中數(shù)據(jù)的讀寫操作。
          api-data

          9.1 創(chuàng)建數(shù)據(jù)模型類

          public class CityTag {
              private String tagName;

              public CityTag(String tagName) {
                  this.tagName = tagName;
              }
                  // 省略Getter/Setter/toString
          }
          @HBaseTable(namespaceName = "default", tableName = "t2", defaultFamilyName = "info")
          public class CityModel {
              @HBaseRowKey
              private String cityId;
              private String cityName;
              private String cityAddress;
              @HBaseColumn(familyName = "detail")
              private Integer cityArea;
              @HBaseColumn(familyName = "detail", toUpperCase = true)
              private Integer totalPopulation;
              @HBaseColumn(familyName = "detail", columnName = "cityTagList")
              private List<CityTag> cityTagList;
              // 省略Getter/Setter/toString
          }
          @HBaseTable注解用于定義 HBase 的表信息
          @HBaseTable(namespaceName = "default", tableName = "t2", defaultFamilyName = "info")
          1)namespaceName:用于指定該表的命名空間,默認(rèn)值:default
          2)tableName:用于指定該表的表名,如果不指定,表名則為類名的組合單詞拆分轉(zhuǎn)小寫加'_'拼接,如:CityModel 對應(yīng)的表名為:city_model。3)defaultFamilyName:如果有字段不特別配置(@HBaseRowKey 注解中的 familyName)列簇名,則使用此處配置的默認(rèn)列簇名。
          @HBaseRowKey注解用于定義某一個屬性字段是用作存儲 rowKey 數(shù)據(jù)的,是必須要設(shè)置的,如:
          @HBaseRowKey
          private String cityId;
          該注解表示 cityId 字段為 rowKey。
          @HBaseColumn注解用于定義 HBase 的列簇和列名信息,如:
          @HBaseColumn(familyName = "detail", columnName = "TOTAL_POPULATION",  toUpperCase = true)
          private Integer totalPopulation;
          1)familyName:指定列簇名,如果不指定,則使用 defaultFamilyName 配置的列簇名。
          2)columnName:指定列名,不指定則默認(rèn)使用字段名的組合單詞拆分轉(zhuǎn)小寫加'_'拼接,如:isVip,對應(yīng)的字段名是:is_vip
          3)toUpperCase:定義字段名是否轉(zhuǎn)大寫,如:isVip -> IS_VIP,默認(rèn)值:false,不做轉(zhuǎn)換。

          9.2 保存數(shù)據(jù)

          @Test
           public void testSaveUser() {
               CityModel cityModel = new CityModel();
               cityModel.setCityId("10001");
               cityModel.setCityName("上海");
               cityModel.setCityAddress("上海市");
               cityModel.setCityArea(10000);
               cityModel.setTotalPopulation(200000);                                   cityModel.setCityTagList(tagNameList.stream().map(CityTag::new).collect(Collectors.toList()));
               CityModel city = tableTemplate.save(cityModel);
          }
          除此之外,保存數(shù)據(jù)時也可以不必構(gòu)造數(shù)據(jù)模型類,而選擇直接構(gòu)造 map 數(shù)據(jù)模型。
          @Test
          public void testToSave() {
              Map<String, Object> data = new HashMap<>();
              data.put("info1:addresses", Arrays.asList("廣州""深圳"));
              data.put("info1:username""leo");
              data.put("info1:age"18);
              data.put("INFO2:IS_VIP"true);
              data.put("info1:pay"10000.1d);
              data.put("info1:create_by""tom");
              data.put("info1:create_time", System.currentTimeMillis());
              Map<String, Object> contactInfo = new HashMap<>(2);
              contactInfo.put("email""[email protected]");
              contactInfo.put("phone""18739577988");
              contactInfo.put("address""浦東新區(qū)");
              data.put("info1:contact_info", contactInfo);
              hBaseTemplate.save("TEST:LEO_USER""10002", data);
              System.out.println("用戶數(shù)據(jù)保存成功!");
          }

          9.3 批量保存數(shù)據(jù)

          @Test
          public void testToSaveBatch() {
              Map<String, Map<String, Object>> data = new HashMap<>(2);

              Map<String, Object> data1 = new HashMap<>(3);
              data1.put("info1:username""kangkang");
              data1.put("info1:age"18);
              data1.put("INFO2:IS_VIP"true);

              Map<String, Object> data2 = new HashMap<>(3);
              data2.put("info1:username""jane");
              data2.put("info1:age"18);
              data2.put("INFO2:IS_VIP"false);

              data.put("12003", data1);
              data.put("11004", data2);

              hBaseTemplate.saveBatch("TEST:LEO_USER", data);
              System.out.println("用戶數(shù)據(jù)批量保存成功!");
          }

          9.4 根據(jù) RowKey 查詢

          @Test
          public void testGetJavaBean() {
              Optional<CityModel> a10001 = tableTemplate.getRow("a10001", CityModel.class);
              Optional<CityModel> a10001F = tableTemplate.getRow("a10001""info", CityModel.class);
              System.out.println(a10001.orElse(new CityModel()));
              System.out.println(a10001F);
          }
          查詢數(shù)據(jù)返回 Map
          @Test
          public void testGetRowToMap() {
              Map<String, String> d1 = tableTemplate.getRowToMap("t1""1001"true);
              JSONArray objects = JSON.parseArray(d1.get("f3:tags"));
              Map<String, String> d2 = tableTemplate.getRowToMap("t1""1002"false);
              List<String> rows = new ArrayList<>(2);
              rows.add("1001");
              rows.add("1002");
              Map<String, Map<String, String>> d3 = tableTemplate.getRowsToMap("t1", rows, true);
              System.out.println(d1);
              System.out.println(d2);
              System.out.println(d3);
          }

          9.5 自定義 RowMapper

          如果你需要自定義轉(zhuǎn)換 Result 對象,則可以使用 RowMapper
          @Test
          public void testGetRowMapper() {
              CityModel cityModel = tableTemplate.getRow("t2""a10001"new RowMapper<CityModel>() {
                  @Override
                  public <R> CityModel mapRow(R r, int rowNum) throws Exception {
                      Result result = (Result) r;
                      if (result == null) {
                          return null;
                      }
                      CityModel c = new CityModel();
                      c.setCityId(Bytes.toString(result.getRow()));
                      c.setCityName(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("city_name"))));
                      c.setCityAddress(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("city_address"))));
                      c.setCityArea(Bytes.toInt(result.getValue(Bytes.toBytes("detail"), Bytes.toBytes("city_area"))));
                      c.setTotalPopulation(Bytes.toInt(result.getValue(Bytes.toBytes("detail"), Bytes.toBytes("TOTAL_POPULATION"))));
                      String value = Bytes.toString(result.getValue(Bytes.toBytes("detail"), Bytes.toBytes("cityTagList")));
                      JSONArray jsonArray = JSON.parseArray(value);
                      List<CityTag> tags = new ArrayList<>(jsonArray.size());
                      for (int i = 0; i < jsonArray.size(); i++) {
                          tags.add(jsonArray.getObject(i, CityTag.class));
                      }
                      c.setCityTagList(tags);
                      return c;
                  }
              }).orElse(new CityModel());
              System.out.println(cityModel);
          }

          9.6 scan 查詢

          普通 scan 查詢
          @Test
          public void testScanWithLimit() {
              ScanQueryParamsBuilder scanQueryParamsBuilder = new ScanQueryParamsBuilder.Builder()
                          .familyName("info")
                          .columnNames(Arrays.asList("city_name""city_address""cityTagList"))
                          .limit(2)
                          .build();
              List<CityModel> cityModels = tableTemplate.scan(scanQueryParamsBuilder, CityModel.class);
              System.out.println(cityModels);
          }
          根據(jù)起止 row 查詢數(shù)據(jù)
          @Test
          public void testScanWithStartAndEndRow() {
              // 不包含endRow的數(shù)據(jù)
              ScanQueryParamsBuilder scanQueryParamsBuilder = new ScanQueryParamsBuilder.Builder()
                          .startRow("a10001")
                          .stopRow("a10002")
                          .build();
              List<CityModel> cityModels = tableTemplate.scan(scanQueryParamsBuilder, CityModel.class);
              System.out.println(cityModels);
          }
          指定過濾器的 scan 查詢
          @Test
          public void testScanWithFilter() {
              ScanQueryParamsBuilder scanQueryParamsBuilder = new ScanQueryParamsBuilder.Builder()
                      .filter(new IHBaseFilter<Filter>() {
                          @Override
                          public Filter customFilter() {
                              List<Filter> filters = new ArrayList<>(2);
                              // 篩選row key 大于b20001的數(shù)據(jù)
                              Filter rowFilter = new RowFilter(CompareFilter.CompareOp.GREATER,
                                      new BinaryComparator("b20001".getBytes()));
                              // 篩選列前綴city_address的數(shù)據(jù)
                              ColumnPrefixFilter columnPrefixFilter = new ColumnPrefixFilter(Bytes.toBytes("city_address"));
                              // 篩選列值與深圳市相等的數(shù)據(jù)
                              ValueFilter valueFilter = new ValueFilter(CompareFilter.CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("深圳市")));
                              // 多過濾器,注意順序
                              filters.add(rowFilter);
                              filters.add(columnPrefixFilter);
                              filters.add(valueFilter);
                              // 需所有條件全部通過
                              FilterList andFilterList = new FilterList(FilterList.Operator.MUST_PASS_ALL, filters);
                              // 滿足其中一個條件即可
                              FilterList orFilterList = new FilterList(FilterList.Operator.MUST_PASS_ONE, filters);
                              return orFilterList;
                          }
                      })
                      .build();
              List<CityModel> cityModels = tableTemplate.scan(scanQueryParamsBuilder, CityModel.class);
              System.out.println(cityModels);
          }

          9.6 刪除數(shù)據(jù)

          @Test
          public void testDeleteData() {
              hBaseTemplate.delete("TEST:LEO_USER""12003");
              hBaseTemplate.delete("TEST:LEO_USER""11004""INFO2");
              hBaseTemplate.delete("TEST:LEO_USER""10001""info1""addresses");
              System.out.println("數(shù)據(jù)刪除完成");
          }
          批量刪除數(shù)據(jù)
          @Test
          public void testDeleteBatch() {
              hBaseTemplate.deleteBatch("TEST:LEO_USER", Arrays.asList("10001""10002"));
              hBaseTemplate.deleteBatch("TEST:LEO_USER", Collections.singletonList("10003"), "INFO2");
              hBaseTemplate.deleteBatch("TEST:LEO_USER", Collections.singletonList("10004"),
                      "info1""age""username");
          }

          10. HQL

          hbase-sdk 從 2.0.6 版本開始,開始提供 HQL 功能,并在 3.0.0 版本中得到極大優(yōu)化,一種以類 SQL 的方式讀寫 HBase 表中的數(shù)據(jù),進(jìn)一步降低了普通 API 的使用復(fù)雜度。HQL 的操作依賴HBaseSqlTemplate來完成,因此在使用之前,需先構(gòu)造好HBaseSqlTemplate的對象實例。
          hql

          10.1 構(gòu)造 HBaseSqlTemplate 的示例

          // 1. 創(chuàng)建HBase SQL操作的模版類HBaseSqlTemplate
          private HBaseSqlTemplate hBaseSqlTemplate = new HBaseTableTemplateImpl.Builder()
                          .properties(getProperties()).build();

          //  把HBase的連接配置信息存儲在Properties中
          Properties getProperties() {
              Properties properties = new Properties();
              properties.setProperty("hbase.zookeeper.quorum""myhbase");
              properties.setProperty("hbase.zookeeper.property.clientPort""2181");
              return properties;
          }

          10.2 創(chuàng)建并注冊HBaseTableSchema

          // 2. 創(chuàng)建HBaseTableSchema
          HBaseTableSchema tableSchema = new HBaseTableSchema.Builder("test:test_sql")
                  .addColumn("f1""id")
                  .addColumn("f1""name")
               // 指定列類型,不指定默認(rèn)是ColumnType.StringType
                  .addColumn("f1""age", ColumnType.IntegerType)
                  .addColumn("f2""address")
               // 指定一個字段是row key
                  .addRow("row_key")
                  .scanBatch(100)
                  .scanCaching(1000)
                  .deleteBatch(100)
                  .scanCacheBlocks(false)
                  .build();

          // 3. 注冊HBaseTableSchema至HBaseSqlContext中
          HBaseSqlContext.registerTableSchema(tableSchema);

          tableSchema.printSchema();
          打印 schema
          printSchema

          10.3 Insert

          插入一條數(shù)據(jù)
          insert into test:test_sql ( f1:id , f1:name , f1:age , f2:address ) values ( '10001' , 'a_leo' , 15 , 'bj' ) where rowKey = 'a10001'
          調(diào)用 insert 保存數(shù)據(jù)
          sqlTemplate.insert(hql);
          插入數(shù)據(jù)時還可以指定一些內(nèi)置的 rowkey function
          -- 對rowKey進(jìn)行md5
          insert into test:test_sql ( f1:id , f1:name , f1:age , f2:address ) values ( '11111' , 'a_leo' , 15 , 'bj' ) where rowKey = md5 ( 'a1111' )

          -- 對rowKey md5取前4位作為前綴用|與原row拼接后形成新的rowKey
          -- md5_prefix暫時不支持對參數(shù)列表的解析
          insert into test:test_sql ( f1:id , f1:name , f1:age , f2:address ) values ( '11111' , 'a_leo' , 15 , 'bj' ) where rowKey = md5_prefix ( 'a1111' )
          row key function 暫時還不支持對參數(shù)列表的解析,暫時只能使用 function ( 'row key 值' )的形式。
          查看新保存的數(shù)據(jù)
          select * from test:test_sql where rowKey = md5 ( 'a1111' )
          select * from test:test_sql where rowKey = md5_prefix ( 'a1111' )
          row_function

          10.4 Select

          select 的調(diào)用方法如下:
          String hsql = "select * from test:test_sql where rowKey = md5_prefix ( 'a1111' )";
          HBaseDataSet dataSet = sqlTemplate.select(hsql);
          dataSet.show()
          1. 根據(jù) rowKey 查詢數(shù)據(jù)
          select * from test:test_sql where rowKey = 'a10001'
          select_by_row
          2. 查詢一批數(shù)據(jù),即:in row keys
          select * from test:test_sql where rowKey in ( 'a10001' , 'a10002' , 'a10003' )
          in_row_keys
          3. 根據(jù) startRowKey 和 endRowKey 掃描數(shù)據(jù)
          select * from test:test_sql where ( startKey = 'a10001' , endKey = 'b20006' )
          -- b20006不會被包含進(jìn)去
          select_limit
          4. 查詢不同版本數(shù)據(jù)
          先保存三個版本數(shù)據(jù)
          save_data_3_version
          查詢多版本數(shù)據(jù)
          select f1:name from test:test_sql where rowKey = 'row_1000' and maxVersion = 3
          select-some-versions
          5. 列值過濾查詢
          列值過濾查詢時需指定 row 的過濾條件,以避免引發(fā)全表掃描
          select * from test:test_sql where ( startKey = 'a10001' , endKey = 'a10006' ) and f1:age <= 18
          select_by_filter_col
          6. limit
          select * from test:test_sql where ( startKey = 'a10001' , endKey = 'a10006' ) and f1:age <= 18 limit 2
          select_limit
          7. 查詢一批 rowkey 數(shù)據(jù)
          select * from test:test_sql where rowKey in ( 'a10001' , 'a10002' , 'a10003' )
          select-in-rows

          10.5 delete

          原始數(shù)據(jù)
          source-data
          刪除某個 row key 的某個字段
          delete f1:age from test:test_sql where rowKey = 'b20004'
          delete-one-col
          指定時間戳刪除數(shù)據(jù)
          原始數(shù)據(jù)如下:
          原始數(shù)據(jù)
          指定時間戳來刪除數(shù)據(jù),由圖示可知,時間戳為 1670579504803 的數(shù)據(jù)已被刪除
          delete f1:age from test:test_sql where rowKey = 'row_10001' and ts = 1670579504803
          delete_data
          delete 的調(diào)用方式:
          @Test
          public void testDeleteSql(){
              String hql = "delete f1:age from test:test_sql where rowKey = 'row_10001'";
              sqlTemplate.delete(hql);
          }

          11. HBaseThriftAPI

          hbase-client中的 API 會直接連接 zookeeper,如果客戶端對 Connection 濫用,可能會造成 zookeeper 的連接被耗盡。
          hbase-thrift不僅具有跨語言的特性,同時也會在底層避免我們直接創(chuàng)建對 zk 的連接。
          但如果直接使用 hbase thrift 的原生 API,你可能會遇到以下幾種情況:
          1. 頻繁創(chuàng)建 TSocket 連接,增加不必要的開銷
          2. 某一時間段內(nèi)可能頻繁創(chuàng)建過多的 TSocket,造成本地短連接過多
          3. 創(chuàng)建完一個 TSocket,間隔時間過長不使用,會被服務(wù)端主動斷開
          為了解決上述問題,hbase-sdk 中采取對 hbase thrift 中的 TSocket 進(jìn)行連接池封裝。

          11.1 創(chuàng)建 thrift api 操作模版類——HBaseThriftTemplate

          hbase-sdk中 HBase Thrift API 連接池的實現(xiàn)是基于 commons-pool2 的,類似 jedis-pool,相關(guān)代碼在hbase-sdk-thrift模塊中。
          使用 thrift api 之前,請先創(chuàng)建 HBaseThriftTemplate 的對象
          HBaseThriftTemplate thriftTemplate = HBaseThriftTemplateFactory.getInstance("localhost"9090);

          HBaseThriftTemplate thriftTemplate = HBaseThriftTemplateFactory.getInstance("localhost"909010);

          HBaseThriftTemplate thriftTemplate = HBaseThriftTemplateFactory.getInstance("localhost"9090, config);
          HBaseThriftTemplate 可接受的參數(shù)類型:
          1. thrift server host
          2. thrift server port
          3. poolSize 連接池大小,設(shè)置后,連接池中核心和最大參數(shù)都將是此值
          4. HBaseThriftPoolConfig config
          config 為連接池配置類,其默認(rèn)配置如下,可按需進(jìn)行修改設(shè)置:
          public class HBaseThriftPoolConfig extends GenericObjectPoolConfig {
              public HBaseThriftPoolConfig() {
                  // 連接池中的最大連接數(shù),默認(rèn)1,根據(jù)服務(wù)端可以容納的最大連接數(shù)和當(dāng)前并發(fā)數(shù)進(jìn)行合理設(shè)置
                  setMaxTotal(1);
                  // 連接池中確保的最少空閑連接數(shù)
                  setMinIdle(1);
                  // 連接池中允許的最大空閑連接數(shù)
                  setMaxIdle(1);
                  // 連接池用盡后,調(diào)用者是否等待,為true時,maxWaitMillis才生效
                  setBlockWhenExhausted(true);
                  // 連接池用盡后,調(diào)用者的最大等待時間,毫秒,默認(rèn)-1,表示永不超時
                  setMaxWaitMillis(6000);
                  // 每次從資源池中拿/歸還連接是否校驗連接的有效性,默認(rèn)false,避免每次使用或歸還連接與服務(wù)端進(jìn)行一次連接開銷
                  setTestOnBorrow(false);
                  setTestOnReturn(false);
                  // 開啟JMX監(jiān)控
                  setJmxEnabled(true);
                  // 是否開啟空閑連接檢測,默認(rèn)false,建議true
                  setTestWhileIdle(true);
                  // 空閑連接的檢測周期,毫秒,默認(rèn)-1不進(jìn)行檢測,此處周期設(shè)置為3分鐘
                  setTimeBetweenEvictionRunsMillis(180 * 1000);
                  // 空閑連接檢測時,每次檢測資源的個數(shù),設(shè)置為-1,就是對所有連接進(jìn)行檢測
                  setNumTestsPerEvictionRun(-1);
                  // 連接池中連接的最小空閑時間,默認(rèn)600000毫秒,10分鐘
                  setMinEvictableIdleTimeMillis(600 * 1000);
                  //硬閑置  3秒沒有占用設(shè)置為閑置, 檢測線程直接剔除閑置,保持的最小空閑數(shù),會被剔除且重新生成 硬閑置設(shè)置之后,軟閑置設(shè)置無效
                  //setMinEvictableIdleTimeMillis(3000);
                  //軟閑置  3秒沒有占用設(shè)置為閑置, 當(dāng)空閑連接>最小空閑數(shù),才執(zhí)行剔除閑置連接,否則維持最小空閑數(shù),即使閑置了也不會剔除
                  //setSoftMinEvictableIdleTimeMillis(3000);
              }
          }

          11.2 保存數(shù)據(jù)

          構(gòu)造數(shù)據(jù)模型類
          @HBaseTable(namespaceName = "test", tableName = "t1", defaultFamilyName = "info")
          public class UserModel {
              @HBaseRowKey
              private String userId;
              @HBaseColumn()
              private String nickName;
              @HBaseColumn(familyName = "detail", columnName = "detailAddress")
              private String detailAddress;
              @HBaseColumn(familyName = "detail", toUpperCase = true)
              private double detailPay;
              // 省略getter、setter
          }
          或選擇直接保存 Map 中的數(shù)據(jù)
          Map<String, Object> data = new HashMap<>();
          data.put("info:nick_name""會飛的豬");
          data.put("detail:DETAIL_PAY"1234.5);
          data.put("detail:detailAddress""上海黃浦區(qū)");
          thriftTemplate.save("test:t1""u10002", data);
          此處有一個注意事項:
          Map<String, Object> data 中的數(shù)據(jù)保存時,所有值均會被轉(zhuǎn)成 String 類型后存儲,而模型類是區(qū)分屬性類型的。所以,模型類轉(zhuǎn)換 Map<String, Object> data 中的數(shù)據(jù)時,可能會遇到字節(jié)操作的異常。

          11.3 查詢數(shù)據(jù)

          @Test
          public void testGetRow() {
              Optional<UserModel> userModel = thriftTemplate.getRow("u10001", UserModel.class);
              System.out.println(userModel);

              Map<String, String> data = thriftTemplate.getRowToMap("test:t1""u10002"false);
              System.out.println(data);
          }
          查詢多條 row key,即:in row keys
          @Test
          public void testGetRows() {
              thriftTemplate.getRows(Arrays.asList("u10001""u21000""u22000"), UserModel.class);

              thriftTemplate.getRows(Arrays.asList("u10001""u21000""u22000"), "detail", UserModel.class);

              thriftTemplate.getRows(Arrays.asList("u10001""u21000""u22000"), "detail", Collections.singletonList("detailAddress"), UserModel.class);
          }
          Map 結(jié)構(gòu)數(shù)據(jù)保存時,會統(tǒng)一把數(shù)據(jù)轉(zhuǎn)換為字符串類型,所以,當(dāng)用 java 實體類綁定時,可能出現(xiàn)報錯情況。

          11.4 Scan 數(shù)據(jù)

          全表掃描所有數(shù)據(jù),并設(shè)置 limit
          @Test
          public void testScanWithLimit() {
              ScanQueryParamsBuilder queryParams = new ScanQueryParamsBuilder.Builder()
                      .limit(2)
                      .build();
              // Map 保存的數(shù)據(jù),與模型類保存的數(shù)據(jù),非string類型不能互通
              List<UserModel> userModelList = thriftTemplate.scan(queryParams, UserModel.class);
              System.out.println(userModelList);
          }
          根據(jù)起止 row key 掃描數(shù)據(jù),不包含 stopRow
          @Test
          public void testScanWithStarAndRow() {
              ScanQueryParamsBuilder queryParams = new ScanQueryParamsBuilder.Builder()
                      .startRow("u10001")
                      .stopRow("u21000")
                      .build();

              List<UserModel> userModelList = thriftTemplate.scan(queryParams, UserModel.class);
              System.out.println(userModelList);
          }
          設(shè)置過濾器掃描,列名為 nick_前綴,且列對應(yīng)值 ascii 碼表比對:>= 不會飛的豬 2 的數(shù)據(jù)被篩選出來:
          @Test
          public void testScanWithFilter() {
              // 設(shè)置過濾器掃描,列名為nick_前綴,且列對應(yīng)值ascii碼比:不會飛的豬2大的被篩選出
              ScanQueryParamsBuilder queryParams = new ScanQueryParamsBuilder.Builder()
                      .filter(new IHBaseFilter<String>() {
                          @Override
                          public String customFilter() {
                              return "ColumnPrefixFilter('nick_') AND ValueFilter(>=, 'binary:不會飛的豬2')";
                              }
                          })
                          .build();

              List<UserModel> userModelList = thriftTemplate.scan(queryParams, UserModel.class);
              System.out.println(userModelList);
          }
          更多 API 的使用可以參考源碼中的測試用例以及相關(guān)的 API 文檔。

          12. 特別鳴謝

          HQL 的語法設(shè)計以及 antlr4 的語法解析,有參考 alibaba 的開源項目 simplehbase,在此特別感謝。simplehbase 感覺是一個被遺棄的項目,針對的 HBase 版本是 0.94, 已經(jīng)有超過 6 年沒有維護(hù)了。
          hbase-sdk 在 simplehbase 的基礎(chǔ)上進(jìn)行重組和解耦,以兼容hbase-sdk原有的框架設(shè)計,并便于以后的擴(kuò)展。

          13. hbase-sdk 目前的不足

          HQL 的 antlr4 解析功能不太完善,對語法的要求比較嚴(yán)格,多一個空格少一個空格貌似都會引起語法錯誤。需后續(xù)優(yōu)化。
          可能還有一些隱藏 BUG,未被發(fā)現(xiàn)。
          可能存在性能不足的地方可以被進(jìn)一步優(yōu)化。
          接口的定義,類的繼承和一些設(shè)計模式的應(yīng)用上,還有進(jìn)一步優(yōu)化的空間。
          因此歡迎各位大佬試用和參與開發(fā),多多提出您寶貴的建議。

          14. 未來計劃

          • HBatis,類似于 MyBatis 的 ORM 框架,以 XML 管理 SQL 的方式維護(hù)集群數(shù)據(jù)的讀寫操作
          • 集成 Hystrix 熔斷框架,實現(xiàn) API 層面的主備集群自動切換功能
          • Thrift 連接池自動擴(kuò)所容的能力
          • 還有更多

          15. 更新日志

          v3.0.0 2022-12-10

          • 對 hbase-sdk 項目做了大量重構(gòu),使 API 的抽象程度更高,同時豐富了原有的功能,也修復(fù)諸多 BUG。
          • 基于 reflectasm 重構(gòu)反射工具類,引入緩存等等,以提升 ORM 映射字段的效率。
          • HQL 功能優(yōu)化
          • 工具類優(yōu)化
          • 引入 findbugs、checkstyle 等插件,并優(yōu)化打包方式

          v2.0.7 2020-12-30

          • HBase Thrift API 上線,以及提供 Thrift API 的連接池實現(xiàn)

          v2.0.6 2020-11-29

          • HQL 功能上線

          v2.0.5 2020-11-14

          • 新增功能與代碼優(yōu)化

          v2.0.3 2020-10-08

          • 大量重構(gòu)和優(yōu)化

          v1.0.5 2020-09-07

          • 完善基礎(chǔ) API 的功能
          • 完成 ORM 特性
          • 模塊拆分
          • ......

          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费日本黄色 | 天天操天天曰天天爱 | 欧美在线视频导航 | 国产精品国产三级国产专播品爱网 | 91丝袜视频 |