ElasticSearch
[TOC]
概述
ES是Lucene的一个封装工具,解决了Lucene配置麻烦,不支持分布式的缺点
ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单
安装
官方下载:https://www.elastic.co/downloads/elasticsearch
然后解压,运行bin路径下的elasticsearch.bat文件


这样就成功运行了,然后在浏览器输入localhost:9200

出现这个界面就代表成功启动
辅助工具Kibana5
在使用MySql的时候,可以用Navcation来进行可视化管理,Kibana5就是可以对ElasticSearch进行可视化管理的一款工具
官方下载:https://www.elastic.co/downloads/kibana
解压然后修改config/kibana.yml,设置elasticsearch.url的值为已启动的ES地址值(一般不需要修改,默认就是对的)
启动Kibana5 : bin\kibana.bat
默认访问地址:http://localhost:5601

成功访问
增删改查操作
首先明确一点,ES是完全遵从了Restful风格的,关于Restful风格,随便一搜一大堆文章,这里就不详细介绍了
在ES中存储数据的行为就叫做索引(indexing),文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以简单的对比传统数据库和ES的对应关系:
关系数据库(MYSQL) -> 数据库DB-> 表TABLE-> 行ROW-> 列Column
ES的基础语法
- 增加:PUT PUT {index}/{type}/{id}
- 修改:同PUT {index}/{type}/{id}
- 删除:DELETE {index}/{type}/{id}
- 查询:GET {index}/{type}/{id}
下面通过几个Demo来进行演示

IK分词器
ES默认对英文文本的分词器支持较好,但和lucene一样,如果需要对中文进行全文检索,那么需要使用中文分词器,同lucene一样,在使用中文全文检索前,需要集成IK分词器
GitHub下载:https://github.com/medcl/elasticsearch-analysis-ik
解压,并将其内容放置于ES根目录/plugins/ik
然后重启ES
测试分词

注意:IK分词器有两种类型,分别是ik_smart分词器和ik_max_word分词器。
ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。
ik_max_word:会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合
索引
ES索引的增删改查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| # 创建索引库
PUT imp { "settings": { "number_of_shards": 5, "number_of_replicas": 1 } } # 查询索引库
GET _cat/indices
# 查看指定索引库 GET _cat/indices/imp
# 修改索引库
# 删除索引库 DELETE imp
|
DSL查询
DSL过滤语句和DSL查询语句非常相似,但是它们的使用目的却不同:DSL过滤查询文档的方式更像是对于我的条件”有”或者”没有”(等于 ;不等于),而DSL查询语句则像是”有多像”(模糊查询)
DSL过滤和DSL查询在性能上的区别:
- 过滤结果可以缓存并应用到后续请求。-> 精确过滤后的结果拿去模糊查询性能高
- 查询语句同时匹配文档,计算相关性,所以更耗时,且不缓存。
- 过滤语句可有效地配合查询语句完成文档过滤
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #DSL查询 GET fueen/person/_search { "query": { "match": { "speak": "高级动物" } } }
# 创建测试数据 PUT fueen/user/5 { "id":5, "sex":"SAUMAG Note10 Pro", "ceagtor":"手机", "money":8000 }
GET fueen/user/_search?_source
# DSL过滤
GET fueen/user/_search { "query": { "bool": { "must": [ {"match": { "ceagtor": "手机" }} ], "filter": { "range": { "money": { "gte": 6000, "lte": 8000 } } } } }, "from": 0, "size": 10, "_source": ["sex","ceagtor","money"], "sort": [ { "money": "desc" } ] }
|
文档映射
ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型
就是规定了每个输入字段值的数据类型
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| # 映射 PUT imp/life/_mapping { "life":{ "properties":{ "id":{ "type":"long" }, "name":{ "type":"text", "analyzer":"ik_smart", "search_analyzer":"ik_smart" } } } }
# 查看文档映射 GET imp/_mapping/life
# 删除映射 DELETE imp
# 动态模板 PUT _template/kof_template { "template": "*", "settings": { "number_of_shards": 1 }, "mappings": { "_default_": { "_all": { "enabled": false }, "dynamic_templates": [ { "string_as_text": { "match_mapping_type": "string", "match": "*_text", "mapping": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word", "fields": { "raw": { "type": "keyword", "ignore_above": 256 } } } } }, { "string_as_keyword": { "match_mapping_type": "string", "mapping": { "type": "keyword" } } } ] } }}
|
集群
为什么需要ES集群
和Redis一样,集群能够做很多事情
ES的集群节点
主节点
node.master=true,代表该节点有成为主资格,主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。一般会把主节点和数据节点分开,node.master=true , node.data=false
数据节点
node.data=true,数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等,数据节点对CPU,IO,内存要求较高,优化节点的时候需要做状态监控,资源不够时要做节点扩充。配置:mode.master=false,mode.data=true
负载均衡节点
当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。配置:mode.master=false,mode.data=false
模拟搭建集群
准备三个ES服务
可以模拟出三个不同的文件,修改不同的端口
配置说明
1 2 3 4 5 6 7 8 9 10 11 12
| # 统一的集群名 cluster.name: my-ealsticsearch # 当前节点名 node.name: node-1 # 对外暴露端口使外网访问 network.host: 127.0.0.1 # 对外暴露端口 http.port: 9201 #集群间通讯端口号 transport.tcp.port: 9301 #集群的ip集合,可指定端口,默认为9300 discovery.zen.ping.unicast.hosts: ["127.0.0.1:9301","127.0.0.1:9302","127.0.0.1:9303"]
|
1 2 3 4 5 6 7 8 9 10 11 12
| # 统一的集群名 cluster.name: my-ealsticsearch # 当前节点名 node.name: node-2 # 对外暴露端口使外网访问 network.host: 127.0.0.1 # 对外暴露端口 http.port: 9202 #集群间通讯端口号 transport.tcp.port: 9302 #集群的ip集合,可指定端口,默认为9300 discovery.zen.ping.unicast.hosts: ["127.0.0.1:9301","127.0.0.1:9302","127.0.0.1:9303"]
|
1 2 3 4 5 6 7 8 9 10 11 12
| # 统一的集群名 cluster.name: my-ealsticsearch # 当前节点名 node.name: node-3 # 对外暴露端口使外网访问 network.host: 127.0.0.1 # 对外暴露端口 http.port: 9203 #集群间通讯端口号 transport.tcp.port: 9303 #集群的ip集合,可指定端口,默认为9300 discovery.zen.ping.unicast.hosts: ["127.0.0.1:9301","127.0.0.1:9302","127.0.0.1:9303"]
|
分别启动三个ES节点 , 访问:http://127.0.0.1:9201/

然后再通过Kiban5去访问,修改默认配置路径为:elasticsearch.url: “http://localhost:9201“

访问成功
Java操作ES
创建一个Maven项目,在pom.xml中加入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> </dependencies>
|
写一个连接ES的工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.ifueen.es;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient;
import java.net.InetAddress; import java.net.UnknownHostException;
public class ESClientUtil {
public static TransportClient getClient(){ Settings settings = Settings.builder() .put("cluster.name","my-ealsticsearch") .put("client.transport.sniff", true).build(); TransportClient client = null; try { client = new PreBuiltTransportClient(settings) .addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9302)); } catch (UnknownHostException e) { e.printStackTrace(); } return client; } }
|
然后开始测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| package com.ifueen.es;
import org.elasticsearch.action.bulk.BulkItemResponse; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequestBuilder; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.update.UpdateRequestBuilder; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHits; import org.junit.Test;
import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map;
public class TestESCluster { TransportClient client = ESClientUtil.getClient();
@Test public void testadd(){
IndexRequestBuilder index = client.prepareIndex("fueen", "person", "1"); Map<String,Object> data = new HashMap<String, Object>(); data.put("id","1"); data.put("username","fueen"); data.put("speak","我们不能失去信仰"); IndexResponse indexResponse = index.setSource(data).get(); System.out.println(indexResponse); client.close();
}
@Test public void testquery(){ GetResponse getFields = client.prepareGet("fueen", "person", "1").get(); System.out.println(getFields.getSource()); }
@Test public void testupdate(){ HashMap<String, Object> map = new HashMap<>(); map.put("id","1"); map.put("username","这个世界会好吗"); map.put("speak","李志"); UpdateRequestBuilder builder = client.prepareUpdate("fueen", "person", "1"); UpdateResponse updateResponse = builder.setDoc(map).get(); System.out.println(updateResponse); client.close(); }
@Test public void testdel(){ DeleteRequestBuilder del = client.prepareDelete("fueen", "person", "1"); DeleteResponse deleteResponse = del.get(); System.out.println(deleteResponse); client.close(); }
@Test public void testbulikadd(){ BulkRequestBuilder builder = client.prepareBulk(); Map<String, Object> map = new HashMap<>(); map.put("id","1"); map.put("username","会沉寂吗"); map.put("speak","我的金桔"); builder.add(client.prepareIndex("fueen","person","1") .setSource(map));
Map<String, Object> map1 = new HashMap<>(); map1.put("id","2"); map1.put("username","会沉寂吗"); map1.put("speak","人民不需要自由"); builder.add(client.prepareIndex("fueen","person","2") .setSource(map1));
BulkResponse bulkItemResponses = builder.get(); Iterator<BulkItemResponse> iterator = bulkItemResponses.iterator(); while (iterator.hasNext()){ BulkItemResponse next = iterator.next(); System.out.println(next.getResponse()); } client.close(); }
@Test public void testbulikquery(){ SearchRequestBuilder fueen = client.prepareSearch("fueen"); fueen.setTypes("person"); fueen.setFrom(0); fueen.setSize(10);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); List<QueryBuilder> must = boolQueryBuilder.must(); must.add(QueryBuilders.matchQuery("username","会沉寂吗"));
SearchResponse searchResponse = fueen.setQuery(boolQueryBuilder).get(); SearchHits hits = searchResponse.getHits(); System.out.println("条数:"+hits.getTotalHits()); hits.forEach(h->{ System.out.println(h); }); client.close(); }
}
|