1.概述

  前面在《ElasticSearch实战-入门》中给大家分享如何搭建这样一个集群,在完成集群的搭建后,今天给大家分享如何实现对应的业务功能模块,下面是今天的分享内容,目录如下所示:

  • 编码实践
  • 效果预览
  • 总结

2.编码实践

  由于 ES 集群支持 Restful 接口,我们可以直接通过 Java 来调用 Restful 接口来查询我们需要的数据结果,并将查询到的结果在在我们的业务界面可视化出来。我们知道在 ES 集群的 Web 管理界面有这样一个入口,如下图所示:

  我们可以在此界面的入口中拼接 JSON 字符串来查询我们想要的结果,下面,我们通过 Java 的 API 去调用 Restful 接口来查询我们想要的结果。

2.1 字符串拼接实现

  接着,我们去实现要查询的核心代码,具体内容实现如下所示:

public String buildQueryString(Map<String, Object> param) throws ParseException {
SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
StringBuilder builder = new StringBuilder("{\"query\":{\"bool\":{\"must\":[");
if (param.get("msgType") != null) {
Integer msgType = (int) param.get("msgType") == 0 ? 2 : 1;
builder.append("{\"term\":{\"msg_type\":").append(msgType).append("}}");
}if (param.get("start") != null && param.get("end") != null) {
String start = String.valueOf(dfs.parse(param.get("start").toString()).getTime()).substring(0, 10);
String end = String.valueOf(dfs.parse(param.get("end").toString()).getTime()).substring(0, 10);
builder.append(",{\"range\":{\"itime\":{\"from\":" + start + ",\"to\":" + end + "}}}");
}
if (param.get("receiverValue") != null) {
builder.append(",{\"wildcard\":{\"receiver_value\":\"*").append(param.get("receiverValue")).append("*\"}}");
}
builder.append("],\"must_not\":[],\"should\":[]}}");
builder.append(",\"sort\":[{\"itime\":\"desc\"}],\"facets\":{}");
builder.append(",\"from\": ").append(param.get("startIndex")).append(",\"size\": ").append(param.get("pageSize")).append("}");
LOG.info("API Query -> " + builder.toString());
return builder.toString();
}

2.2 查询实现核心代码

  接着是实现查询的核心代码,具体内容实现如下所示:

public SerachResponse<ApiSent> querySent(Map<String, Object> param) {
SerachResponse<ApiSent> search_result = null;
try {
long time = System.currentTimeMillis();
ResponseWrapper wrapper = httpUtils.sendJson(configService.loadConfig(Configure.API_SENT), buildQueryString(param));
if (wrapper.responseCode == HttpStatus.SC_OK) {
search_result = _gson.fromJson(wrapper.responseContent, new TypeToken<SerachResponse<ApiSent>>() {
}.getType());
LOG.info(String.format("API query ES spent time=%sms", (System.currentTimeMillis() - time)));
return search_result;
} else {
LOG.info(String.format("API query ES spent time=%sms", (System.currentTimeMillis() - time)));
LOG.error(String.format("api sent request es server response not 200,response=%s,exception=%s", wrapper.error, wrapper.exceptionString));
}
} catch (Exception ex) {
LOG.error(String.format("parsed es sent data exception.", ex));
}
return search_result; }
  • Configure类
public class Configure {
public static final String API_SENT = "API_SENT";

2.3 DAO层获取 ES 集群的连接信息

public class ConfigService {

    private static Log logger = LogFactory.getLog(ConfigService.class);

    @Autowired
private ConfigDao configDao; @Cacheable("sysConfigCache")
public String loadConfig(String type) {
String value = configDao.getConfig(type);
logger.info(String.format("Load Config,type=%s,value=%s", type, value));
return value;
}
}
  • ConfigDao接口
public interface ConfigDao {

    String getConfig(String type);

}

  其对应的实现内容如下所示:

<select id="getConfig" parameterType="String" resultType="String">
  select value from t_system_config where type=#{type}
</select>

  DB库存储的 ES 连接信息,如下图所示:

2.4 HTTP 接口的实现代码

  关于 HttpUtils 的代码实现较为简单,这里直接附上代码的实现内容,如下所示:

  • IHttpUtils 接口
public interface IHttpUtils {
public ResponseWrapper sendJson(String url, String content);
}
  • HttpUtils 类实现接口
public class HttpUtils implements IHttpUtils {

    private static Logger LOG = Logger.getLogger(HttpUtils.class.getName());
protected static Gson _gson = new Gson(); protected void initSSL() {
try {
TrustManager[] tmCerts = new javax.net.ssl.TrustManager[1];
tmCerts[0] = new SimpleTrustManager();
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
sc.init(null, tmCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier hv = new SimpleHostnameVerifier();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception e) {
LOG.error("init SSL exception.", e);
}
} @Override
public ResponseWrapper sendJson(String url, String content) {
return sendJson(url, content, null);
} @Override
public ResponseWrapper sendJson(String url, String content, String authCode) {
return sendRequest(url, content, METHOD_POST, authCode, CONTENT_TYPE_JSON);
} public ResponseWrapper sendRequest(String url, String content, String method, String authCode,
String contentType) {
LOG.info("Send request to - " + url + ", with content - " + content);
HttpURLConnection conn = null;
OutputStream out = null;
StringBuffer sb = new StringBuffer();
cn.jpush.utils.ResponseWrapper wrapper = new ResponseWrapper(); try {
if (StringUtils.isSSL(url)) {
initSSL();
} if (METHOD_GET.equals(method)) {
if (!Strings.isNullOrEmpty(content)) url += "?" + content;
}
URL aUrl = new URL(url);
wrapper.address = aUrl.getHost(); conn = (HttpURLConnection) aUrl.openConnection();
conn.setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT);
conn.setReadTimeout(DEFAULT_SOCKET_TIMEOUT);
conn.setUseCaches(false);
conn.setRequestMethod(method);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Accept-Charset", CHARSET);
conn.setRequestProperty("Charset", CHARSET);
conn.setRequestProperty("Authorization", authCode);
conn.setRequestProperty("Send-Source", "portal");
conn.setRequestProperty("Content-Type", contentType); if (METHOD_POST.equals(method)) {
conn.setDoOutput(true);
byte[] data = content.getBytes(CHARSET);
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
out = conn.getOutputStream();
out.write(data);
out.flush();
} else {
conn.setDoOutput(false);
}
int status = conn.getResponseCode();
InputStream in = null;
if (status == 200) {
in = conn.getInputStream();
} else {
in = conn.getErrorStream();
}
InputStreamReader reader = new InputStreamReader(in, CHARSET);
char[] buff = new char[1024];
int len;
while ((len = reader.read(buff)) > 0) {
sb.append(buff, 0, len);
} String responseContent = sb.toString();
wrapper.responseCode = status;
wrapper.responseContent = responseContent; String quota = conn.getHeaderField(RATE_LIMIT_QUOTA);
String remaining = conn.getHeaderField(RATE_LIMIT_Remaining);
String reset = conn.getHeaderField(RATE_LIMIT_Reset);
wrapper.setRateLimit(quota, remaining, reset); if (status == 200) {
LOG.debug("Succeed to get response - 200 OK");
LOG.debug("Response Content - " + responseContent); } else if (status > 200 && status < 400) {
LOG.warn("Normal response but unexpected - responseCode:" + status
+ ", responseContent:" + responseContent); } else {
LOG.warn("Got error response - responseCode:" + status + ", responseContent:"
+ responseContent); switch (status) {
case 400:
LOG.error("Your request params is invalid. Please check them according to error message.");
wrapper.setErrorObject();
break;
case 401:
LOG.error("Authentication failed! Please check authentication params according to docs.");
wrapper.setErrorObject();
break;
case 403:
LOG.error("Request is forbidden! Maybe your is listed in blacklist?");
wrapper.setErrorObject();
break;
case 410:
LOG.error("Request resource is no longer in service. Please according to notice on official website.");
wrapper.setErrorObject();
case 429:
LOG.error("Too many requests! Please review your request quota.");
wrapper.setErrorObject();
break;
case 500:
case 502:
case 503:
case 504:
LOG.error("Seems encountered server error. Maybe is in maintenance? Please retry later.");
break;
default:
LOG.error("Unexpected response.");
} } } catch (SocketTimeoutException e) {
if (e.getMessage().contains(KEYWORDS_READ_TIMED_OUT)) {
LOG.error(KEYWORDS_READ_TIMED_OUT, e);
}
wrapper.exceptionString = e.getMessage(); } catch (IOException e) {
LOG.error(KEYWORDS_CONNECT_TIMED_OUT, e);
wrapper.exceptionString = e.getMessage(); } finally {
if (null != out) {
try {
out.close();
} catch (IOException e) {
LOG.error("Failed to close stream.", e);
}
}
if (null != conn) {
conn.disconnect();
}
}
LOG.info(String.format("Send Response to - %s, Response Wrapper - %s", url, wrapper));
return wrapper;
}
}

3.截图预览

  下面给大家附上一张业务界面可视化的数据结果预览图,如下图所示:

  上图为我发送的测试数据,通过收集模块将我发送的数据收集并存储到 ES 集群,通过接口代码将这部分数据可视化到业务界面进行展示。

4.总结

  总体来说,ES 集群从搭建部署到编码实现都较为简单,在使用 JSON 字符串拼接查询时需要细心点,后续有时间可以为大家分享下 ES 的查询的效率,及其他方面的性能指标。

5.结束语

  这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!

ElasticSearch实战-编码实践的更多相关文章

  1. Kafka项目实战-用户日志上报实时统计之编码实践

    1.概述 本课程的视频教程地址:<Kafka实战项目之编码实践>  该课程我以用户实时上报日志案例为基础,带着大家去完成各个KPI的编码工作,实现生产模块.消费模块,数据持久化,以及应用调 ...

  2. Hadoop项目实战-用户行为分析之编码实践

    1.概述 本课程的视频教程地址:<用户行为分析之编码实践> 本课程以用户行为分析案例为基础,带着大家去完成对各个KPI的编码工作,以及应用调度工作,让大家通过本课程掌握Hadoop项目的编 ...

  3. 后端开发实践系列之四——简单可用的CQRS编码实践

    本文只讲了一件事情:软件模型中存在读模型和写模型之分,CQRS便为此而生. 20多年前,Bertrand Meyer在他的<Object-Oriented Software Constructi ...

  4. ElasticSearch实战-入门

    http://www.cnblogs.com/smartloli/ 1.概述 今天接着<ElasticSearch实战-日志监控平台>一文来给大家分享后续的学习,在<ElasticS ...

  5. ElasticSearch实战-日志监控平台

    1.概述 在项目业务倍增的情况下,查询效率受到影响,这里我们经过讨论,引进了分布式搜索套件——ElasticSearch,通过分布式搜索来解决当下业务上存在的问题.下面给大家列出今天分析的目录: El ...

  6. ElasticSearch实战

    ElasticSearch实战-入门 1.概述 今天接着<ElasticSearch实战-日志监控平台>一文来给大家分享后续的学习,在<ElasticSearch实战-日志监控平台& ...

  7. 七、Kafka 用户日志上报实时统计之编码实践

    一.数据生产实现 1.配置数据生产模块 项目基础配置所包含的内容,如下所示: •项目工程的文件配置 •集群连接信息配置 •开发演示 2.实现 Flume 到 Kafka 模块 实现 Flume 到 K ...

  8. [Shell]bash的良好编码实践

    最好的bash脚本不仅可以工作,而且以易于理解和修改的方式编写.很多好的编码实践都是来自使用一致的变量名称和一致的编码风格.验证用户提供的参数是否正确,并检查命令是否能成功运行,以及长时间运行是否能保 ...

  9. I-team 博客全文检索 Elasticsearch 实战

    一直觉得博客缺点东西,最近还是发现了,当博客慢慢多起来的时候想要找一篇之前写的博客很是麻烦,于是作为后端开发的楼主觉得自己动手丰衣足食,也就有了这次博客全文检索功能Elasticsearch实战,这里 ...

随机推荐

  1. centos 7 一些命令

    su 切换到管理员账户cd 'wo shi mu lu'ls 查看 当前目录或者文件tar -xvzf pip-10.0.1.tar.gz 解压 文件systemctl restart network ...

  2. MySQL数据查询之单表查询

    单表查询 简单查询 - 创建表 DROP TABLE IF EXISTS `person`; CREATE TABLE `person` ( `id` ) NOT NULL AUTO_INCREMEN ...

  3. Python select模块学习

    select 是常用的异步socket 处理方法 一般用法: # iwtd,owtd,ewtd 分别为需要异步处理的读socket队列, 写socket队列(一般不用), 和错误socket队列, 返 ...

  4. PowerShell 使用.NetFramework

    我们都知道,由于PowerShell是基于.NETFramework建立的所以它能够具备访问.NET的能力,因为.NET提供了庞大的数据类库,所以我们可以很好的使用PowerShell去完成一些Pow ...

  5. leetcode 315. Count of Smaller Numbers After Self 两种思路

    说来惭愧,已经四个月没有切 leetcode 上的题目了. 虽然工作中很少(几乎)没有用到什么高级算法,数据结构,但是我一直坚信 "任何语言都会过时,只有数据结构和算法才能永恒". ...

  6. Chapter5 生长因子、受体和癌症

    一.Src蛋白是一种蛋白激酶 可以磷酸化不同的底物,调节不同的通路 Src激酶主要磷酸化酪氨酸残基,而别的激酶主要磷酸化色氨酸.苏氨酸残基 二.EGF受体拥有酪氨酸激酶功能 胞内结构域有Src蛋白的同 ...

  7. HashMap TreeMap的区别

    Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复就覆盖了),但允许值重复.Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快 ...

  8. 【repost】jQuery笔记总结

    第一节 jQuery初步认知 jQuery概述 JQuery概念 javascript概念 基于Js语言的API和语法组织逻辑,通过内置window和document对象,来操作内存中的DOM元素 J ...

  9. ReactNative学习笔记(七)Navigator的使用

    前言 Navigator主要用于ReactNative中的跳转,中文文档: http://reactnative.cn/docs/0.39/using-navigators.html 懒得打字介绍更多 ...

  10. nginx并发模型与traffic_server并发模型简单比较

    ginx并发模型: nginx 的进程模型采用的是prefork方式,预先分配的worker子进程数量由配置文件指定,默认为1,不超过1024.master主进程创建监听套接口,fork子进程以后,由 ...