1. 执行流程

2. Solr Cloud实现

http://blog.csdn.net/u011462328/article/details/53008344

3. HBase实现

1) 自定义Observer

① 代码

  1. package cn.bfire.coprocessor;
  2. import com.typesafe.config.Config;
  3. import com.typesafe.config.ConfigFactory;
  4. import org.apache.hadoop.hbase.Cell;
  5. import org.apache.hadoop.hbase.CellUtil;
  6. import org.apache.hadoop.hbase.client.Delete;
  7. import org.apache.hadoop.hbase.client.Durability;
  8. import org.apache.hadoop.hbase.client.Put;
  9. import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
  10. import org.apache.hadoop.hbase.coprocessor.ObserverContext;
  11. import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
  12. import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
  13. import org.apache.hadoop.hbase.util.Bytes;
  14. import org.apache.solr.common.SolrInputDocument;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17. import java.io.IOException;
  18. import java.util.List;
  19. /**
  20. * 为hbase提供二级索引的协处理器 Coprocesser
  21. */
  22. public class UserDevPiSolrObserver extends BaseRegionObserver {
  23. //加载配置文件属性
  24. static Config config = ConfigFactory.load("userdev_pi_solr.properties");
  25. //log记录
  26. private static final Logger logger = LoggerFactory.getLogger(UserDevPiSolrObserver.class);
  27. @Override
  28. public void postPut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
  29. // 获取行键值
  30. String rowkey = Bytes.toString(put.getRow());
  31. //实例化 SolrDoc
  32. SolrInputDocument doc = new SolrInputDocument();
  33. //添加Solr uniqueKey值
  34. doc.addField("rowkey", rowkey);
  35. // 获取需要索引的列
  36. String[] hbase_columns = config.getString("hbase_column").split(",");
  37. // 获取需要索引的列的值并将其添加到SolrDoc
  38. for (int i = 0; i < hbase_columns.length; i++) {
  39. String colName = hbase_columns[i];
  40. String colValue = "";
  41. // 获取指定列
  42. List<Cell> cells = put.get("cf".getBytes(), colName.getBytes());
  43. if (cells != null) {
  44. try {
  45. colValue = Bytes.toString(CellUtil.cloneValue(cells.get(0)));
  46. } catch (Exception ex) {
  47. logger.error("添加solrdoc错误", ex);
  48. }
  49. }
  50. doc.addField(colName, colValue);
  51. }
  52. //发送数据到本地缓存
  53. SolrIndexTools.addDoc(doc);
  54. }
  55. @Override
  56. public void postDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException {
  57. //得到rowkey
  58. String rowkey = Bytes.toString(delete.getRow());
  59. //发送数据本地缓存
  60. String solr_collection = config.getString("solr_collection");
  61. SolrIndexTools.delDoc(rowkey);
  62. }
  63. }
  1. package cn.bfire.coprocessor;
  2. import com.typesafe.config.Config;
  3. import com.typesafe.config.ConfigFactory;
  4. import org.apache.solr.client.solrj.impl.CloudSolrClient;
  5. import org.apache.solr.common.SolrInputDocument;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import java.util.Timer;
  11. import java.util.TimerTask;
  12. import java.util.concurrent.Semaphore;
  13. /**
  14. * solr索引处理客户端
  15. * 注意问题,并发提交时,需要线程协作资源
  16. */
  17. public class SolrIndexTools {
  18. //加载配置文件属性
  19. static Config config = ConfigFactory.load("userdev_pi_solr.properties");
  20. //log记录
  21. private static final Logger logger = LoggerFactory.getLogger(SolrIndexTools.class);
  22. //实例化solr的client
  23. static CloudSolrClient client = null;
  24. //添加批处理阈值
  25. static int add_batchCount = config.getInt("add_batchCount");
  26. //删除的批处理阈值
  27. static int del_batchCount = config.getInt("del_batchCount");
  28. //添加的集合缓冲
  29. static List<SolrInputDocument> add_docs = new ArrayList<SolrInputDocument>();
  30. //删除的集合缓冲
  31. static List<String> del_docs = new ArrayList<String>();
  32. static final List<String> zkHosts = new ArrayList<String>();
  33. static {
  34. logger.info("初始化索引调度........");
  35. String zk_host = config.getString("zk_host");
  36. String[] data = zk_host.split(",");
  37. for (String zkHost : data) {
  38. zkHosts.add(zkHost);
  39. }
  40. client = new CloudSolrClient.Builder().withZkHost(zkHosts).build();
  41. // 获取Solr collection
  42. String solr_collection = config.getString("solr_collection");
  43. client.setDefaultCollection(solr_collection);
  44. client.setZkClientTimeout(10000);
  45. client.setZkConnectTimeout(10000);
  46. //启动定时任务,第一次延迟1s执行,之后每隔指定时间30S执行一次
  47. Timer timer = new Timer();
  48. timer.schedule(new SolrCommit(), config.getInt("first_delay") * 1000, config.getInt("interval_commit_index") * 1000);
  49. }
  50. public static class SolrCommit extends TimerTask {
  51. @Override
  52. public void run() {
  53. logger.info("索引线程运行中........");
  54. //只有等于true时才执行下面的提交代码
  55. try {
  56. semp.acquire();//获取信号量
  57. if (add_docs.size() > 0) {
  58. client.add(add_docs);//添加
  59. }
  60. if (del_docs.size() > 0) {
  61. client.deleteById(del_docs);//删除
  62. }
  63. //确保都有数据才提交
  64. if (add_docs.size() > 0 || del_docs.size() > 0) {
  65. client.commit();//共用一个提交策略
  66. //清空缓冲区的添加和删除数据
  67. add_docs.clear();
  68. del_docs.clear();
  69. } else {
  70. logger.info("暂无索引数据,跳过commit,继续监听......");
  71. }
  72. } catch (Exception e) {
  73. logger.error("间隔提交索引数据出错!", e);
  74. } finally {
  75. semp.release();//释放信号量
  76. }
  77. }
  78. }
  79. /**
  80. * 添加数据到临时存储中,如果
  81. * 大于等于batchCount时,就提交一次,
  82. * 再清空集合,其他情况下走对应的时间间隔提交
  83. *
  84. * @param doc 单个document对象
  85. */
  86. public static void addDoc(SolrInputDocument doc) {
  87. commitIndex(add_docs, add_batchCount, doc, true);
  88. }
  89. /***
  90. * 删除的数据添加到临时存储中,如果大于
  91. * 对应的批处理就直接提交,再清空集合,
  92. * 其他情况下走对应的时间间隔提交
  93. *
  94. * @param rowkey 删除的rowkey
  95. */
  96. public static void delDoc(String rowkey) {
  97. commitIndex(del_docs, del_batchCount, rowkey, false);
  98. }
  99. // 任何时候,保证只能有一个线程在提交索引,并清空集合
  100. final static Semaphore semp = new Semaphore(1);
  101. /***
  102. * 此方法需要加锁,并且提交索引时,与时间间隔提交是互斥的
  103. * 百分百确保不会丢失数据
  104. *
  105. * @param datas 用来提交的数据集合
  106. * @param count 对应的集合提交数量
  107. * @param doc   添加的单个doc
  108. * @param isAdd 是否为添加动作
  109. */
  110. public synchronized static void commitIndex(List datas, int count, Object doc, boolean isAdd) {
  111. try {
  112. semp.acquire();//获取信号量
  113. if (datas.size() >= count) {
  114. if (isAdd) {
  115. client.add(datas);//添加数据到服务端中
  116. } else {
  117. client.deleteById(datas);//删除数据
  118. }
  119. client.commit();//提交数据
  120. datas.clear();//清空临时集合
  121. }
  122. } catch (Exception e) {
  123. e.printStackTrace();
  124. logger.error("按阈值" + (isAdd == true ? "添加" : "删除") + "操作索引数据出错!", e);
  125. } finally {
  126. datas.add(doc);//添加单条数据
  127. semp.release();//释放信号量
  128. }
  129. }
  130. }
    1. <pre code_snippet_id="1962705" snippet_file_name="blog_20161102_1_8333418" style="font-family: Consolas; font-size: 11.3pt; background-color: rgb(255, 255, 255);">pom文件配置</pre>
    2. <pre style="font-family:Consolas; font-size:11.3pt; background-color:rgb(255,255,255)"><pre code_snippet_id="1962705" snippet_file_name="blog_20161227_4_7977704" name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
    3. <project xmlns="http://maven.apache.org/POM/4.0.0"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    6. <modelVersion>4.0.0</modelVersion>
    7. <groupId>cn.gcks</groupId>
    8. <artifactId>hbase</artifactId>
    9. <version>1.0-SNAPSHOT</version>
    10. <dependencies>
    11. <!-- https://mvnrepository.com/artifact/org.apache.solr/solr-solrj -->
    12. <dependency>
    13. <groupId>org.apache.solr</groupId>
    14. <artifactId>solr-solrj</artifactId>
    15. <version>6.2.1</version>
    16. <exclusions>
    17. <exclusion>
    18. <groupId>org.slf4j</groupId>
    19. <artifactId>slf4j-api</artifactId>
    20. </exclusion>
    21. </exclusions>
    22. </dependency>
    23. <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->
    24. <dependency>
    25. <groupId>org.apache.hbase</groupId>
    26. <artifactId>hbase-client</artifactId>
    27. <version>1.1.2</version>
    28. <exclusions>
    29. <exclusion>
    30. <groupId>org.apache.hadoop</groupId>
    31. <artifactId>*</artifactId>
    32. </exclusion>
    33. </exclusions>
    34. </dependency>
    35. <dependency>
    36. <groupId>org.apache.hbase</groupId>
    37. <artifactId>hbase-server</artifactId>
    38. <version>1.1.2</version>
    39. <exclusions>
    40. <exclusion>
    41. <groupId>org.apache.hadoop</groupId>
    42. <artifactId>*</artifactId>
    43. </exclusion>
    44. </exclusions>
    45. </dependency>
    46. <!-- https://mvnrepository.com/artifact/com.typesafe/config -->
    47. <dependency>
    48. <groupId>com.typesafe</groupId>
    49. <artifactId>config</artifactId>
    50. <version>1.3.1</version>
    51. </dependency>
    52. </dependencies>
    53. </project></pre></pre>
    54. <pre style="font-family:Consolas; font-size:11.3pt; background-color:rgb(255,255,255)"><p>
    55. </p><p><span style="font-weight:bold; color:rgb(0,128,0); font-size:11.3pt; background-color:rgb(228,228,255)">userdev_pi_solr.properties</span></p><p></p><pre code_snippet_id="1962705" snippet_file_name="blog_20161227_5_7563783" name="code" class="plain">#需要建索引的列
    56. hbase_column=oid,pi_id,statdate
    57. # solr的collection名称
    58. solr_collection=userdev_pi_day
    59. #定义solr的url地址,如果是cloud模式,可以配置多个以逗号分隔
    60. zk_host=1.1.1.1:2181,1.1.1.2:2181,1.1.1.3:2181
    61. #调度第一次开始时,延迟多少秒执行
    62. first_delay=10
    63. #后台线程多久提交一次索引,单位秒
    64. interval_commit_index=30
    65. #添加索引的批处理数量
    66. add_batchCount=10000
    67. #删除索引的批处理数量
    68. del_batchCount=2000</pre><br><br><p></p><p></p><p>② 打包代码并上传到<span style="font-family:Calibri">hdfs</span><span style="font-family:宋体">目录</span></p><p>③ 修改<span style="font-family:Calibri">HBase</span><span style="font-family:宋体">表(设置自定义</span><span style="font-family:Calibri">observer</span><span style="font-family:宋体">所在</span><span style="font-family:Calibri">hdfs</span><span style="font-family:宋体">位置,以及指定自定义</span><span style="font-family:Calibri">Observer</span><span style="font-family:宋体">全类名)</span></p><p>alter 'radius:raduserlog', 'coprocessor' => 'hdfs://<span style="color:rgb(0,112,192)">/apps/hbase/jars/hbase_solr.jar</span>|cn.bfire.coprocessor.UserDevPiSolrObserver|'</p><p>2) 数据查询代码</p><p></p><pre code_snippet_id="1962705" snippet_file_name="blog_20161102_4_5934630" name="code" class="java">package cn.bfire.solr;
    69. import org.apache.commons.logging.Log;
    70. import org.apache.commons.logging.LogFactory;
    71. import org.apache.hadoop.hbase.Cell;
    72. import org.apache.hadoop.hbase.CellUtil;
    73. import org.apache.hadoop.hbase.HBaseConfiguration;
    74. import org.apache.hadoop.hbase.TableName;
    75. import org.apache.hadoop.hbase.client.*;
    76. import org.apache.hadoop.hbase.util.Bytes;
    77. import org.apache.solr.client.solrj.SolrQuery;
    78. import org.apache.solr.client.solrj.impl.CloudSolrClient;
    79. import org.apache.solr.client.solrj.response.QueryResponse;
    80. import org.apache.solr.common.SolrDocument;
    81. import org.apache.solr.common.SolrDocumentList;
    82. import org.apache.solr.common.SolrInputDocument;
    83. import java.util.ArrayList;
    84. import java.util.Collection;
    85. import java.util.List;
    86. public class SolrCloudTest {
    87. public static final Log LOG = LogFactory.getLog(SolrCloudTest.class);
    88. private static CloudSolrClient cloudSolrClient;
    89. private static Connection connection;
    90. private static Table table;
    91. private static Get get;
    92. private static String defaultCollection = "userdev_pi_day";
    93. private static String hbaseTable = "<span style="font-family: Arial, Helvetica, sans-serif;">userdev_pi_day</span><span style="font-family: Arial, Helvetica, sans-serif;">";</span>
    94. List<Get> list = new ArrayList<Get>();
    95. static {
    96. final List<String> zkHosts = new ArrayList<String>();
    97. zkHosts.add("1.1.1.1:2181");
    98. zkHosts.add("1.1.1.2:2181");
    99. zkHosts.add("1.1.1.3:2181");
    100. cloudSolrClient = new CloudSolrClient.Builder().withZkHost(zkHosts).build();
    101. final int zkClientTimeout = 10000;
    102. final int zkConnectTimeout = 10000;
    103. cloudSolrClient.setDefaultCollection(defaultCollection);
    104. cloudSolrClient.setZkClientTimeout(zkClientTimeout);
    105. cloudSolrClient.setZkConnectTimeout(zkConnectTimeout);
    106. try {
    107. connection = ConnectionFactory.createConnection(HBaseConfiguration.create());
    108. table = connection.getTable(TableName.valueOf(hbaseTable));
    109. } catch (Exception e) {
    110. e.printStackTrace();
    111. }
    112. }
    113. private void addIndex(CloudSolrClient cloudSolrClient) throws Exception {
    114. Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
    115. for (int i = 0; i <= 100; i++) {
    116. SolrInputDocument doc = new SolrInputDocument();
    117. String key = "";
    118. key = String.valueOf(i);
    119. doc.addField("rowkey", key);
    120. doc.addField("usermac", key + "usermac");
    121. doc.addField("userid", key + "userid");
    122. doc.addField("usertype", key + "usertype");
    123. doc.addField("city_id", key + "city_id");
    124. docs.add(doc);
    125. }
    126. LOG.info("docs info:" + docs + "\n");
    127. cloudSolrClient.add(docs);
    128. cloudSolrClient.commit();
    129. }
    130. public void search(CloudSolrClient cloudSolrClient, String Str) throws Exception {
    131. SolrQuery query = new SolrQuery();
    132. query.setRows(100);
    133. query.setQuery(Str);
    134. LOG.info("query string: " + Str);
    135. QueryResponse response = cloudSolrClient.query(query);
    136. SolrDocumentList docs = response.getResults();
    137. System.out.println("文档个数:" + docs.getNumFound()); //数据总条数也可轻易获取
    138. System.out.println("查询时间:" + response.getQTime());
    139. System.out.println("查询总时间:" + response.getElapsedTime());
    140. for (SolrDocument doc : docs) {
    141. String rowkey = (String) doc.getFieldValue("rowkey");
    142. get = new Get(Bytes.toBytes(rowkey));
    143. list.add(get);
    144. }
    145. Result[] res = table.get(list);
    146. for (Result rs : res) {
    147. Cell[] cells = rs.rawCells();
    148. for (Cell cell : cells) {
    149. System.out.println("============");
    150. System.out.println(new String(CellUtil.cloneRow(cell)));
    151. System.out.println(new String(CellUtil.cloneFamily(cell)));
    152. System.out.println(new String(CellUtil.cloneQualifier(cell)));
    153. System.out.println(new String(CellUtil.cloneValue(cell)));
    154. System.out.println("============");
    155. break;
    156. }
    157. }
    158. table.close();
    159. }
    160. public static void main(String[] args) throws Exception {
    161. cloudSolrClient.connect();
    162. SolrCloudTest solrt = new SolrCloudTest();
    163. //            solrt.addIndex(cloudSolrClient);
    164. solrt.search(cloudSolrClient, "userid:11111");
    165. cloudSolrClient.close();
    166. }
    167. }
    168. </pre><br><br><p></p><p></p><pre></pre><pre></pre></pre>
    169. <pre></pre>
    170. <link rel="stylesheet" href="http://static.blog.csdn.net/public/res-min/markdown_views.css?v=2.0">

HBase + Solr Cloud实现HBase二级索引的更多相关文章

  1. HBase学习(四) 二级索引 rowkey设计

    HBase学习(四) 一.HBase的读写流程 画出架构 1.1 HBase读流程 Hbase读取数据的流程:1)是由客户端发起读取数据的请求,首先会与zookeeper建立连接2)从zookeepe ...

  2. 使用ElasticSearch赋能HBase二级索引 | 实践一年后总结

    前言:还记得那是2018年的一个夏天,天气特别热,我一边擦汗一边听领导大刀阔斧的讲述自己未来的改革蓝图.会议开完了,核心思想就是:我们要搞一个数据大池子,要把公司能灌的数据都灌入这个大池子,然后让别人 ...

  3. 「从零单排HBase 12」HBase二级索引Phoenix使用与最佳实践

    Phoenix是构建在HBase上的一个SQL层,能让我们用标准的JDBC APIs对HBase数据进行增删改查,构建二级索引.当然,开源产品嘛,自然需要注意“避坑”啦,阿丸会把使用方式和最佳实践都告 ...

  4. 基于Solr实现HBase的二级索引

    文章来源:http://www.open-open.com/lib/view/open1421501717312.html 实现目的: 由于hbase基于行健有序存储,在查询时使用行健十分高效,然后想 ...

  5. hbase基于solr配置二级索引

    一.概述 Hbase适用于大表的存储,通过单一的RowKey查询虽然能快速查询,但是对于复杂查询,尤其分页.查询总数等,实现方案浪费计算资源,所以可以针对hbase数据创建二级索引(Hbase Sec ...

  6. CDH使用Solr实现HBase二级索引

      一.为什么要使用Solr做二级索引二.实时查询方案三.部署流程3.1 安装HBase.Solr3.2 增加HBase复制功能3.3创建相应的 SolrCloud 集合3.4 创建 Lily HBa ...

  7. HBase协处理器同步二级索引到Solr(续)

    一. 已知的问题和不足二.解决思路三.代码3.1 读取config文件内容3.2 封装SolrServer的获取方式3.3 编写提交数据到Solr的代码3.4 拦截HBase的Put和Delete操作 ...

  8. HBase协处理器同步二级索引到Solr

    一. 背景二. 什么是HBase的协处理器三. HBase协处理器同步数据到Solr四. 添加协处理器五. 测试六. 协处理器动态加载 一. 背景 在实际生产中,HBase往往不能满足多维度分析,我们 ...

  9. Lily HBase Indexer同步HBase二级索引到Solr丢失数据的问题分析

    一.问题描述二.分析步骤2.1 查看日志2.2 修改Solr的硬提交2.3 寻求StackOverFlow帮助2.4 修改了read-row="never"后,丢失部分字段2.5 ...

随机推荐

  1. LeetCode--112--路径总和

    问题描述: 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和. 说明: 叶子节点是指没有子节点的节点. 示例:  给定如下二叉树,以及目标和 s ...

  2. 20170714xlVba多个工作簿转多个Word文档表格

    Public Sub SameFolderGather() Application.ScreenUpdating = False Application.DisplayAlerts = False A ...

  3. 20170609批量生成WORD合同

    Sub NextSeven_CodeFrame() Application.ScreenUpdating = False Application.DisplayAlerts = False Appli ...

  4. Blog Post Rating CodeForces - 806E (线段树二分)

    题目链接 题目大意: 有一个博客, 初始分数为$0$, 有$n$个人, 第$i$个人有一个期望值$a_i$, 如果第$i$个人浏览博客时,博客赞数高于$a_i$博客分数$-1$, 低于$+1$, 相等 ...

  5. zabbix3.0.4 配置邮件报警

    试验环境: LAMP环境 (LNMP环境已经成功了,为了避免干扰,我另一台LAMP主机) ### 我在做实验之前,作了时间同步,不知道这个有木有影响,一起说一下吧! yum -y install nt ...

  6. UVA-11214 Guarding the Chessboard (迭代加深搜索)

    题目大意:在一个国际象棋盘上放置皇后,使得目标全部被占领,求最少的皇后个数. 题目分析:迭代加深搜索,否则超时. 小技巧:用vis[0][r].vis[1][c].vis[2][r+c].vis[c- ...

  7. 贪心(二)NYOJ14题

    #include <iostream> #include<cmath> #include "algorithm" using namespace std; ...

  8. OC 方法和函数

    /* 方法 1.对象方法都是以减号 - 2.对象方法的声明必须写在@interface和@end之间 对象方法的实现必须写在@implementation和@end之间 3.对象方法只能由对象来调用 ...

  9. Python笔记初识

    Python笔记初识

  10. net负载均衡服务器架构网址

    https://blog.csdn.net/orichisonic/article/details/71122291 https://blog.csdn.net/huangxiangec/articl ...