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. 20170528xlVBA凑数一例

    Public Sub MakeUp() Dim Sht As Worksheet Set Sht = ThisWorkbook.Worksheets("设置") Dim Total ...

  2. 移动端web开发技巧(转)

    原文链接:http://liujinkai.com/2015/06/06/mobile-web-skill/ 移动端web开发技巧 这是一个最好的时代,因为我们站在潮流中:但也是一个最坏的时代,因为我 ...

  3. 『Sklearn』数据划分方法

    原理介绍 K折交叉验证: KFold,GroupKFold,StratifiedKFold, 留一法: LeaveOneGroupOut,LeavePGroupsOut,LeaveOneOut,Lea ...

  4. zzuli 1726 迷宫 BFS(题意)

    1726: 迷宫 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 502  Solved: 80 SubmitStatusWeb Board Descri ...

  5. UVA-1252 Twenty Questions (状压DP)

    题目大意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同)最小需要多少次询问? 题目分析:定义dp(s,a ...

  6. Leetcode 113

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

  7. JavaScript 运行机制详解:Event Loop——续

    转自:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 五.定时器 除了放置异步任务的事件,"任务队列"还可以放置定时事 ...

  8. entest1

      1◆ ai I   2◆ ai I ir ɜː ie i:   3◆ u: ʌ ɜː ə   ui u: ure ʊə

  9. POJ 3264 RMQ水题

    题目大意就是有很多牛.告诉你每只牛的高度.然后有很多个询问.输出该区间内的最大身高差.也就是用RMQ求最大值最小值.貌似还可以用线段树.然而,我还不会线段树.....T_T 可能是太多组数据了.cin ...

  10. windows 开发者神器 tc – total command和替代品

    作为开发者,windows上开发时,会运用一些神器,比如:total commander,搜索目录.查看文件.批量重命名等非常方便. tc是收费版的,有个免费的替代版本Just manager:htt ...