欢迎访问我的个人博客:www.ifueen.com
ES是Lucene的一个封装工具,解决了Lucene配置麻烦,不支持分布式的缺点
ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单
官方下载:https://www.elastic.co/downloads/elasticsearch
然后解压,运行bin路径下的elasticsearch.bat文件
这样就成功运行了,然后在浏览器输入localhost:9200
出现这个界面就代表成功启动
在使用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的基础语法
下面通过几个Demo来进行演示
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索引的增删改查
# 创建索引库
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查询
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)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型
就是规定了每个输入字段值的数据类型
案例
# 映射
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服务
可以模拟出三个不同的文件,修改不同的端口
配置说明
# 统一的集群名
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"]
# 统一的集群名
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"]
# 统一的集群名
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”
访问成功
创建一个Maven项目,在pom.xml中加入
<dependencies>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>transportartifactId>
<version>5.2.2version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-apiartifactId>
<version>2.7version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.7version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>compilescope>
dependency>
dependencies>
写一个连接ES的工具类
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;
/**
* ES集群的工具类
*/
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;
}
}
然后开始测试
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();
}
}