---------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处] 
文章出处:http://blog.csdn.net/sdksdk0/article/details/53966430
作者:朱培      ID:sdksdk0     

--------------------------------------------------------------------------------------------

首先祝大家2017新年快乐,我今天分享的是通过ElasticSearch与hbase进行整合的一个搜索案例,这个案例涉及的技术面比较广,首先你得有JAVAEE的基础,要会SSM,而且还要会大数据中的hdfs、zookeeper、hbase以及ElasticSearch和kibana。环境部署在4台centos7上。主机名为node1-node4。这里假设你已经安装好了zookeeper、hadoop、hbase和ElasticSearch还有kibana,我这里使用的是hadoop2.5.2,ElasticSearch用的你是2.2,kibana是4.4.1。我这里的环境是 hadoop是4台在node1-node4, zookeeper是3台再node1-node3,,ElasticSearch是3台在node1-node3,kibana是一台在node1上。该系统可以对亿万数据查询进行秒回,是一般的关系型数据库很难做到的。在IntelliJ IDEA 中进行代码编写。环境搭建我这里就不啰嗦,相信大家作为一名由经验的开发人员来说都是小事一桩。文末提供源码下载链接。

一、ElasticSearch和Hbase

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。 Elasticsearch的性能是solr的50倍。

HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩、
实时读写的分布式数据库
– 利用Hadoop HDFS作为其文件存储系统,利用Hadoop MapReduce来处理
HBase中的海量数据,利用Zookeeper作为其分布式协同服务
– 主要用来存储非结构化和半结构化的松散数据(列存 NoSQL 数据库)

二、需求分析&服务器环境设置

主要是做一个文章的搜索。有文章标题、作者、摘要、内容四个主要信息。效果图如下:这里样式我就没怎么设置了。。。。想要好看一点的可以自己加css。

服务器:

在3台centos7中部署,主机名为node1-node3.安装好ElasticSearch并配置好集群,

1.     解压

2.     修改config/elasticsearch.yml    (注意要顶格写,冒号后面要加一个空格)

a)      Cluster.name: tf   (同一集群要一样)

b)      Node.name: node-1  (同一集群要不一样)

c)       Network.Host: 192.168.44.137  这里不能写127.0.0.1

3.     解压安装kibana

4.     再congfig目录下的kibana.yml中修改elasticsearch.url

5.     安装插件

Step 1: Install Marvel into Elasticsearch:

bin/plugin install license
bin/plugin install marvel-agent

Step 2: Install Marvel into Kibana

bin/kibana plugin --install elasticsearch/marvel/latest

Step 3: Start Elasticsearch and Kibana

bin/elasticsearch
bin/kibana

启动好elasticsearch集群后,

然后启动zookeeper、hdfs、hbase。zkService.sh start  、start-all.sh、start-hbase.sh。

接下来就是剩下编码步骤了。

三、编码开发

1、首先在IntelliJ IDEA中新建一个maven工程,加入如下依赖。

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency> <!-- spring 3.2 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.0.RELEASE</version>
</dependency> <!-- JSTL -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.10</version>
</dependency> <!-- elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>2.2.0</version>
</dependency> <!-- habse -->
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.1.3</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency> </dependencies>

2、Dao层

	private Integer id;
private String title; private String describe; private String content; private String author;

实现其getter/setter方法。

3、数据准备

在桌面新建一个doc1.txt文档,用于把我们需要查询的数据写入到里面,这里我只准备了5条数据。中间用tab键隔开。

4、在hbase中建立表。表名师doc,列族是cf。

public static void main(String[] args) throws Exception {
HbaseUtils hbase = new HbaseUtils();
//创建一张表
	hbase.createTable("doc","cf");

}

/**
* 创建一张表
* @param tableName
* @param column
* @throws Exception
*/
public void createTable(String tableName, String column) throws Exception {
if(admin.tableExists(TableName.valueOf(tableName))){
System.out.println(tableName+"表已经存在!");
}else{
HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(tableName));
tableDesc.addFamily(new HColumnDescriptor(column.getBytes()));
admin.createTable(tableDesc);
System.out.println(tableName+"表创建成功!");
}
}

5、导入索引。这一步的时候确保你的hdfs和hbase以及elasticsearch是处于开启状态。

  @Test
public void createIndex() throws Exception {
List<Doc> arrayList = new ArrayList<Doc>();
File file = new File("C:\\Users\\asus\\Desktop\\doc1.txt");
List<String> list = FileUtils.readLines(file,"UTF8");
for(String line : list){
Doc Doc = new Doc();
String[] split = line.split("\t");
System.out.print(split[0]);
int parseInt = Integer.parseInt(split[0].trim());
Doc.setId(parseInt);
Doc.setTitle(split[1]);
Doc.setAuthor(split[2]);
Doc.setDescribe(split[3]);
Doc.setContent(split[3]);
arrayList.add(Doc);
}
HbaseUtils hbaseUtils = new HbaseUtils();
for (Doc Doc : arrayList) {
try {
//把数据插入hbase
hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+"", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_TITLE, Doc.getTitle());
hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+"", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_AUTHOR, Doc.getAuthor());
hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+"", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_DESCRIBE, Doc.getDescribe());
hbaseUtils.put(hbaseUtils.TABLE_NAME, Doc.getId()+"", hbaseUtils.COLUMNFAMILY_1, hbaseUtils.COLUMNFAMILY_1_CONTENT, Doc.getContent());
//把数据插入es
Esutil.addIndex("tfjt","doc", Doc);
} catch (Exception e) {
e.printStackTrace();
}
}
}

数据导入成功之后可以在服务器上通过命令查看一下:

curl -XGET http://node1:9200/tfjt/_search

7、搜索。

在这里新建了一个工具类Esutil.java,主要用于处理搜索的。注意,我们默认的elasticsearch是9200端口的,这里数据传输用的是9300,不要写成9200了,然后就是集群名字为tf,也就是前面配置的集群名。还有就是主机名node1-node3,这里不能写ip地址,如果是本地测试的话,你需要在你的window下面配置hosts文件。

public class Esutil {
public static Client client = null; /**
* 获取客户端
* @return
*/
public static Client getClient() {
if(client!=null){
return client;
}
Settings settings = Settings.settingsBuilder().put("cluster.name", "tf").build();
try {
client = TransportClient.builder().settings(settings).build()
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node1"), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node2"), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node3"), 9300));
} catch (UnknownHostException e) {
e.printStackTrace();
}
return client;
} public static String addIndex(String index,String type,Doc Doc){
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("id", Doc.getId());
hashMap.put("title", Doc.getTitle());
hashMap.put("describe", Doc.getDescribe());
hashMap.put("author", Doc.getAuthor()); IndexResponse response = getClient().prepareIndex(index, type).setSource(hashMap).execute().actionGet();
return response.getId();
} public static Map<String, Object> search(String key,String index,String type,int start,int row){
SearchRequestBuilder builder = getClient().prepareSearch(index);
builder.setTypes(type);
builder.setFrom(start);
builder.setSize(row);
//设置高亮字段名称
builder.addHighlightedField("title");
builder.addHighlightedField("describe");
//设置高亮前缀
builder.setHighlighterPreTags("<font color='red' >");
//设置高亮后缀
builder.setHighlighterPostTags("</font>");
builder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
if(StringUtils.isNotBlank(key)){
// builder.setQuery(QueryBuilders.termQuery("title",key));
builder.setQuery(QueryBuilders.multiMatchQuery(key, "title","describe"));
}
builder.setExplain(true);
SearchResponse searchResponse = builder.get(); SearchHits hits = searchResponse.getHits();
long total = hits.getTotalHits();
Map<String, Object> map = new HashMap<String,Object>();
SearchHit[] hits2 = hits.getHits();
map.put("count", total);
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (SearchHit searchHit : hits2) {
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
HighlightField highlightField = highlightFields.get("title");
Map<String, Object> source = searchHit.getSource();
if(highlightField!=null){
Text[] fragments = highlightField.fragments();
String name = "";
for (Text text : fragments) {
name+=text;
}
source.put("title", name);
}
HighlightField highlightField2 = highlightFields.get("describe");
if(highlightField2!=null){
Text[] fragments = highlightField2.fragments();
String describe = "";
for (Text text : fragments) {
describe+=text;
}
source.put("describe", describe);
}
list.add(source);
}
map.put("dataList", list);
return map;
} // public static void main(String[] args) {
// Map<String, Object> search = Esutil.search("hbase", "tfjt", "doc", 0, 10);
// List<Map<String, Object>> list = (List<Map<String, Object>>) search.get("dataList");
// }
}

8、使用spring控制层处理

在里面的spring配置这里就不说了,代码文末提供。

	@RequestMapping("/search.do")
public String serachArticle(Model model,
@RequestParam(value="keyWords",required = false) String keyWords,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "3") Integer pageSize){
try {
keyWords = new String(keyWords.getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Map<String,Object> map = new HashMap<String, Object>();
int count = 0;
try {
map = Esutil.search(keyWords,"tfjt","doc",(pageNum-1)*pageSize, pageSize);
count = Integer.parseInt(((Long) map.get("count")).toString());
} catch (Exception e) {
logger.error("查询索引错误!{}",e);
e.printStackTrace();
}
PageUtil<Map<String, Object>> page = new PageUtil<Map<String, Object>>(String.valueOf(pageNum),String.valueOf(pageSize),count);
List<Map<String, Object>> articleList = (List<Map<String, Object>>)map.get("dataList");
page.setList(articleList);
model.addAttribute("total",count);
model.addAttribute("pageNum",pageNum);
model.addAttribute("page",page);
model.addAttribute("kw",keyWords);
return "index.jsp";
}

9、页面

<center>
<form action="search.do" method="get">
<input type="text" name="keyWords" />
<input type="submit" value="百度一下">
<input type="hidden" value="1" name="pageNum">
</form>
<c:if test="${! empty page.list }">
<h3>百度为您找到相关结果约${total}个</h3>
<c:forEach items="${page.list}" var="bean">
<a href="/es/detailDocById/${bean.id}.do">${bean.title}</a>
<br/>
<br/>
<span>${bean.describe}</span>
<br/>
<br/>
</c:forEach> <c:if test="${page.hasPrevious }">
<a href="search.do?pageNum=${page.previousPageNum }&keyWords=${kw}"> 上一页</a>
</c:if>
<c:forEach begin="${page.everyPageStart }" end="${page.everyPageEnd }" var="n">
<a href="search.do?pageNum=${n }&keyWords=${kw}"> ${n }</a>   
</c:forEach> <c:if test="${page.hasNext }">
<a href="search.do?pageNum=${page.nextPageNum }&keyWords=${kw}"> 下一页</a>
</c:if>
</c:if>
</center>

10、项目发布

在IntelliJ IDEA 中配置好常用的项目,这里发布名Application context名字为es,当然你也可以自定义设置。

最终效果如下:搜索COS会得到结果,速度非常快。

总结:这个案例的操作流程还是挺多的,要有细心和耐心,特别是服务器配置,各种版本要匹配好,不然会出各种头疼的问题,当然了,这个还是需要有一定基础,不然搞不定这个事情。。。。。

源码地址:https://github.com/sdksdk0/es

Elasticsearch+Hbase实现海量数据秒回查询的更多相关文章

  1. HBase多条件及分页查询的一些方法

    HBase是Apache Hadoop生态系统中的重要一员,它的海量数据存储能力,超高的数据读写性能,以及优秀的可扩展性使之成为最受欢迎的NoSQL数据库之一.它超强的插入和读取性能与它的数据组织方式 ...

  2. 【转】FlashBack总结之闪回查询与闪回表

    本文主要介绍利用UNDO表空间的闪回技术,主要包括:闪回表,闪回版本查询,闪回事务查询,闪回查询.这些闪回技术实现从回滚段中读取表中一定时间内操作过的数据,可用来进行数据比对,或者修正意外提交造成的错 ...

  3. oracle闪回查询

    一.引言 程序中用到需要同步oracle更新和删除数据,于是考虑利用oracle的闪回查询机制来实现. 利用该机制首先需要oracle启用撤销表空间自动管理回滚信息,并根据实际情况设置对数据保存的有效 ...

  4. Oracle的回收站和闪回查询机制(一)

    实际工作中,我们经常会遇到一些情况,误删除某些表或某些表的某些记录,这时候就需要我们将这些记录重新插入进去.如何才能解决这个问题呢? Oracle的Flashback query(闪回查询)为我们解决 ...

  5. Flashback Query、Flashback Table(快速闪回查询、快速闪回表)

    Flashback Query闪回查询 flashback query是基于undo表空间的闪回,与之相关的参数如下: SQL> show parameter undo NAME         ...

  6. 已知要闪回的大致时间使用基于as of scn的闪回查询

    基本判断出要恢复误操作的dml的时间可以使用如下的方法进行数据的恢复: example: 一.创建test表 -------create table flashback_asof------ crea ...

  7. Oracle闪回查询恢复delete删除数据

    Flashback query(闪回查询)原理 Oracle根据undo信息,利用undo数据,类似一致性读取方法,可以把表置于一个删除前的时间点(或SCN),从而将数据找回. Flashback q ...

  8. ElasticSearch 5学习(10)——结构化查询(包括新特性)

    之前我们所有的查询都属于命令行查询,但是不利于复杂的查询,而且一般在项目开发中不使用命令行查询方式,只有在调试测试时使用简单命令行查询,但是,如果想要善用搜索,我们必须使用请求体查询(request ...

  9. 闪回查询(SELECT AS OF)

    使用Flashback Query的场景包括如下: 摘自官档 Recovering lost data or undoing incorrect, committed changes. For exa ...

随机推荐

  1. Hadoop API:遍历文件分区目录,并根据目录下的数据进行并行提交spark任务

    hadoop api提供了一些遍历文件的api,通过该api可以实现遍历文件目录: import java.io.FileNotFoundException; import java.io.IOExc ...

  2. Struts(十六):通过CURD来学习Struts流程及ModelDriven的用法

    背景: 从一个Member的增删改查,来了解Struts2的运行原理及学习ModelDriven拦截器.Preparable拦截器. 新建项目实现列表的展示及删除功能: web.xml <?xm ...

  3. Bellman-Ford算法的改进---SPFA算法

    传送门: Dijkstra Bellman-Ford SPFA Floyd 1.算法思想 Bellman-Ford算法时间复杂度比较高,在于Bellman-Ford需要递推n次,每次递推需要扫描所有的 ...

  4. AWS stolen CPU

    故事的开头是这样的: 一天我正在吃饭,突然就收到了服务器告警(cpu high load),吓的我饭也没吃好,只吃了三碗就回去处理故障了,我在监控上看到了这样子的图: 看见了吧,吃饭那段时间cpu一下 ...

  5. 【阿里聚安全·安全周刊】 全美警局已普遍拥有破解 iPhone 的能力 | 女黑客破解任天堂Switch,称硬件漏洞无法修复

    本周的七个关键词: 破解 iPhone丨 女黑客破解任天堂丨假的身份证 丨 扫黄打非丨华盛顿特区发现手机间谍设备 丨 Telegram被俄罗斯监管机构告上法庭丨价值5万美金的Firefox浏览器漏洞 ...

  6. 使用REST风格完成MVC前后端分离

    一个具有REST风格项目的基本特征: 具有统一响应结构 前后台数据流转机制(HTTP消息与Java对象的互相转化机制) 统一的异常处理机制 参数验证机制 Cors跨域请求机制 鉴权机制 一:统一响应结 ...

  7. jdk 动态代理源码分析

    闲来无事,撸撸源码 使用方法 直接看代码吧.. package com.test.demo.proxy; import java.lang.reflect.InvocationHandler; imp ...

  8. “百度杯”CTF比赛 九月场_SQLi

    题目在i春秋ctf大本营 看网页源码提示: 这边是个大坑,访问login.php发现根本不存在注入点,看了wp才知道注入点在l0gin.php 尝试order by语句,发现3的时候页面发生变化,说明 ...

  9. Redis常用命令--Lists

    List是一个双向链表,按照插入顺序排序,可以添加一个元素到头部或者尾部.当对一个空key执行插入操作的时候会创建一个新表. 如果要清空列表,则会杀出对应的key空间. 在List中保存了头节点和未节 ...

  10. [BJOI 2010]次小生成树Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...