elasticsearch 搭建-集群-java应用
搭建
首先下载最新的elasticsearch安装版本:
elasticsearch下载。
下载最新的elasticsearch 0.90.1版本。下载完成后。解压缩在安装目录。
在cmd命令行进入安装目录,再进入 bin目录,运行elasticsearch.bat命令:
启动成功后。在浏览器中输入:http://localhost:9200/
{
"ok" : true,
"status" : 200,
"name" : "Cletus Kasady",
"version" : {
"number" : "0.90.1",
"snapshot_build" : false
},
"tagline" : "You Know, for Search"
}
表示安装成功了。
elasticsearch插件elasticsearch-head安装:
在cmd命令行中进入安装目录,再进入 bin目录,运行以下命令:
plugin -install mobz/elasticsearch-head
然后安装成功后,在浏览器中输入:http://localhost:9200/_plugin/head/,可以看到效果。
具体安装步骤也可以参考:https://github.com/mobz/elasticsearch-head
如果不用安装命令,也可以直接下载安装。
https://github.com/mobz/elasticsearch-head
下载安装包。
1.在cmd命令行中进入安装目录,看是否有plugins目录,如果没有,则创建(第一次时,没有,需要创建)。
2.进入plugins目录,创建head目录
3.进入head目录,创建_site目录
4.解压下载的elasticsearch-head-master.zip,将其elasticsearch-head-master目录下的所有文件放入_site目录中。
5.再次重新启动elasticsearch。在浏览器中输入:http://localhost:9200/_plugin/head/查看结果。
elasticsearch插件bigdesk安装:
在cmd命令行中进入安装目录,再进入 bin目录,运行以下命令:
plugin -install lukas-vlcek/bigdesk
然后安装成功后,在浏览器中输入:http://localhost:9200/_plugin/bigdesk/,可以看到效果。
具体安装步骤也可以参考:https://github.com/lukas-vlcek/bigdesk
如果不用安装命令,也可以直接下载安装。
https://github.com/lukas-vlcek/bigdesk
下载安装包。
1.在cmd命令行中进入安装目录,看是否有plugins目录,如果没有,则创建(第一次时,没有,需要创建)。
2.进入plugins目录,创建bigdesk目录
3.进入bigdesk目录,创建_site目录
4.解压下载的bigdesk-master.zip,将其bigdesk-master目录下的所有文件放入_site目录中。
5.再次重新启动elasticsearch。在浏览器中输入:http://localhost:9200/_plugin/bigdesk/查看结果。
集群配置
elasticsearch的config文件夹里面有两个配置文件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来记录日志的,所以logging.yml里的设置按普通log4j配置文件来设置就行了。下面主要讲解下elasticsearch.yml这个文件中可配置的东西。
配置es的集群名称,默认是elasticsearch,es会自动发现在同一网段下的es,如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。
- cluster.name: elasticsearch
节点名,默认随机指定一个name列表中名字,该列表在es的jar包中config文件夹里name.txt文件中,其中有很多作者添加的有趣名字。 -------自己的配置是第1个节点node-01 第二个节点node-02,文档的介绍是这个节点会自动装配的.
- node.name: "Franz Kafka"
指定该节点是否有资格被选举成为node,默认是true,es是默认集群中的第一台机器为master,如果这台机挂了就会重新选举master。
- node.master: true
指定该节点是否存储索引数据,默认为true。
- node.data: true
master和data同时配置会产生一些奇异的效果:
1) 当master为false,而data为true时,会对该节点产生严重负荷;
2) 当master为true,而data为false时,该节点作为一个协调者;
3) 当master为false,data也为false时,该节点就变成了一个负载均衡器。
设置默认索引分片个数,默认为5片。
- index.number_of_shards: 5
设置默认索引副本个数,默认为1个副本。
- index.number_of_replicas: 1
设置配置文件的存储路径,默认是es根目录下的config文件夹。
- path.conf: /path/to/conf
设置索引数据的存储路径,默认是es根目录下的data文件夹
- path.data: /path/to/data
可以设置多个存储路径,用逗号隔开,例:
- path.data: /path/to/data1,/path/to/data2
设置临时文件的存储路径,默认是es根目录下的work文件夹。
- path.work: /path/to/work
设置日志文件的存储路径,默认是es根目录下的logs文件夹
- path.logs: /path/to/logs
设置插件的存放路径,默认是es根目录下的plugins文件夹
- path.plugins: /path/to/plugins
强制所有内存锁定,不要搞什么swap的来影响性能
设置为true来锁住内存。因为当jvm开始swapping时es的效率会降低,所以要保证它不swap,可以把ES_MIN_MEM和ES_MAX_MEM两个环境变量设置成同一个值,并且保证机器有足够的内存分配给es。同时也要允许elasticsearch的进程可以锁住内存,linux下可以通过`ulimit -l unlimited`命令。
- bootstrap.mlockall: true
设置绑定的ip地址,可以是ipv4或ipv6的,默认为0.0.0.0。
- network.bind_host: 192.168.0.1
设置其它节点和该节点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址。
- network.publish_host: 192.168.0.1
这个参数是用来同时设置bind_host和publish_host上面两个参数。
- network.host: 192.168.0.1
设置节点间交互的tcp端口,默认是9300。
- transport.tcp.port: 9300
设置是否压缩tcp传输时的数据,默认为false,不压缩。
- transport.tcp.compress: true
设置对外服务的http端口,默认为9200。
- http.port: 9200
设置内容的最大容量,默认100mb
- http.max_content_length: 100mb
是否使用http协议对外提供服务,默认为true,开启。
- http.enabled: false
网络配置
- #network.tcp.keep_alive : true
- #network.tcp.send_buffer_size : 8192
- #network.tcp.receive_buffer_size : 8192
自动发现相关配置
- #discovery.zen.fd.connect_on_network_disconnect : true
- #discovery.zen.initial_ping_timeout : 10s
- #discovery.zen.fd.ping_interval : 2s
- #discovery.zen.fd.ping_retries : 10
The gateway snapshot interval (only applies to shared gateways).
- #index.gateway.snapshot_interval : 1s
分片异步刷新时间间隔
- #index.refresh_interval : -1
Set to an actual value (like 0-all) or false to disable it.
- index.auto_expand_replicas
Set to true to have the index read only. false to allow writes and metadata changes.
- index.blocks.read_only
Set to true to disable read operations against the index.
- index.blocks.read
Set to true to disable write operations against the index.
- index.blocks.write
Set to true to disable metadata operations against the index.
- index.blocks.metadata
Lucene index term间隔,仅用于新创建的doc
- index.term_index_interval
Lucene reader term index divisor
- index.term_index_divisor
When to flush based on operations.
- index.translog.flush_threshold_ops
When to flush based on translog (bytes) size.
- index.translog.flush_threshold_size
When to flush based on a period of not flushing.
- index.translog.flush_threshold_period
Disables flushing. Note, should be set for a short interval and then enabled.
- index.translog.disable_flush
The maximum size of filter cache (per segment in shard). Set to -1 to disable.
- index.cache.filter.max_size
The expire after access time for filter cache. Set to -1 to disable.
- index.cache.filter.expire
merge policy
All the settings for the merge policy currently configured. A different merge policy can’t be set.
A node matching any rule will be allowed to host shards from the index.
- index.routing.allocation.include.*
A node matching any rule will NOT be allowed to host shards from the index.
- index.routing.allocation.exclude.*
Only nodes matching all rules will be allowed to host shards from the index.
- index.routing.allocation.require.*
Controls the total number of shards allowed to be allocated on a single node. Defaults to unbounded (-1).
- index.routing.allocation.total_shards_per_node
When using local gateway a particular shard is recovered only if there can be allocated quorum shards in the cluster. It can be set to quorum (default), quorum-1 (or half), full and full-1. Number values are also supported, e.g. 1.
- index.recovery.initial_shards
Disables temporarily the purge of expired docs.
- index.ttl.disable_purge
默认索引合并因子
- #index.merge.policy.merge_factor : 100
- #index.merge.policy.min_merge_docs : 1000
- #index.merge.policy.use_compound_file : true
- #indices.memory.index_buffer_size : 5%
Gateway相关配置
当集群期望节点达不到的时候,集群就会处于block,无法正常索引和查询,说明集群中某个节点未能正常启动,这正是我们期望的效果,block住,避免照成数据的不一致。
gateway的类型,默认为local即为本地文件系统,可以设置为本地文件系统,分布式文件系统,hadoop的HDFS,和amazon的s3服务器,其它文件系统的设置方法下次再详细说。
- gateway.type: local
设置集群中N个节点启动时进行数据恢复,默认为1。
- gateway.recover_after_nodes: 1
设置初始化数据恢复进程的超时时间,默认是5分钟。
- gateway.recover_after_time: 5m
设置这个集群中节点的数量,默认为2,一旦这N个节点启动,就会立即进行数据恢复。
- gateway.expected_nodes: 2
初始化数据恢复时,并发恢复线程的个数,默认为4。
- cluster.routing.allocation.node_initial_primaries_recoveries: 4
添加删除节点或负载均衡时并发恢复线程的个数,默认为4。
- cluster.routing.allocation.node_concurrent_recoveries: 2
设置数据恢复时限制的带宽,如入100mb,默认为0,即无限制。
- indices.recovery.max_size_per_sec: 0
设置这个参数来限制从其它分片恢复数据时最大同时打开并发流的个数,默认为5。
- indices.recovery.concurrent_streams: 5
设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)。
- discovery.zen.minimum_master_nodes: 1
设置集群中自动发现其它节点时ping连接超时时间,默认为3秒,对于比较差的网络环境可以高点的值来防止自动发现时出错。
- discovery.zen.ping.timeout: 3s
- discovery.zen.ping.multicast.enabled: false
设置是否打开多播发现节点,默认是true。
当禁用multcast广播的时候,可以手动设置集群的节点ip
设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。
- discovery.zen.ping.unicast.hosts: ["host1", "host2:port", "host3[portX-portY]"]
下面是一些查询时的慢日志参数设置
- index.search.slowlog.level: TRACE
- index.search.slowlog.threshold.query.warn: 10s
- index.search.slowlog.threshold.query.info: 5s
- index.search.slowlog.threshold.query.debug: 2s
- index.search.slowlog.threshold.query.trace: 500ms
- index.search.slowlog.threshold.fetch.warn: 1s
- index.search.slowlog.threshold.fetch.info: 800ms
- index.search.slowlog.threshold.fetch.debug:500ms
- index.search.slowlog.threshold.fetch.trace: 200ms
1.设置cache大小和过期时间。
- index.cache.field.max_size
- index.cache.field.expire
例如设置:
//index中每个segment中可包含的最大的entries数目
- index.cache.field.max_size: 50000
//过期时间为10分钟
- index.cache.field.expire: 10m
2.改变cache类型。
- index.cache.field.type: soft
在做集群的时候 http.port: 9201 和 transport.tcp.port: 9301 不需要手动设定,如果集群发现了端口号 占用的话,会自动的跳转下一个端口 结果显示
默认类型为resident, 字面意思是常驻(居民), 一直增加,直到内存 耗尽。 改为soft就是当内存不足的时候,先clear掉 占用的,然后再往内存中放。设置为soft后,相当于设置成了相对的内存大小。resident的话,除非内存够大。
3.对数据进行处理。
文章中提到的是减小字段值长度,如将大写转成小写。
这点上,实际中可能将数据精炼。当然, 也可以把要做facet的字段做一个转化,用int型代替。
关于string转化int呢, 可以参考M大神的: https://github.com/medcl/elasticsearch-analysis-string2int
Java开发应用
Maven 管理 pox.xml
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>0.1.2</version>
</dependency>
Java实现增删改查
package org.dennisit.elastic.process;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.sf.json.JSONObject;
import org.dennisit.entity.Student;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* 增加数据
* @author 高国藩
* @date 2015年6月12日 下午8:07:56
*
*/
public class Insert {
/**
* ES 索引值 表空间
*/
private static final String type = "st_tb";
private static final String indexname = "st_in";
/**
* 增加多条数据
* @author 高国藩
* @date 2015年6月12日 下午8:08:50
*/
@Test
public void insertList() {
List<String> jsonData = this.getInitJsonData();
this.createIndexResponse(indexname, type, jsonData);
}
/** 增加数据的时候富裕一个id号码,便于删除和更新数据*/
@Test
public void insertOne() {
JSONObject Json = JSONObject.fromObject(new Student(9, "康师傅3", "32"));
this.createIndexResponse(indexname, type, Json.toString(),"123456");
}
/**
* 建立索引,索引建立好之后,会在elasticsearch-0.20.6\data\elasticsearch\nodes\0创建所以你看
* @param indexName 为索引库名,一个es集群中可以有多个索引库。 名称必须为小写
* @param indexType Type为索引类型,是用来区分同索引库下不同类型的数据的,一个索引库下可以有多个索引类型。
* @param jsondata json格式的数据集合
*/
public void createIndexResponse(String indexname, String type,
List<String> jsondata) {
// 创建索引库 需要注意的是.setRefresh(true)这里一定要设置,否则第一次建立索引查找不到数据
IndexRequestBuilder requestBuilder = client.prepareIndex(indexname,
type).setRefresh(true);
for (int i = 0; i < jsondata.size(); i++) {
requestBuilder.setSource(jsondata.get(i)).execute().actionGet();
}
}
/**
* 创建索引
*
* @param client
* @param jsondata
* @return
*/
public IndexResponse createIndexResponse(String indexname, String type,
String jsondata,String id) {
IndexResponse response = client.prepareIndex(indexname, type,id)
.setSource(jsondata).execute().actionGet();
return response;
}
/**
* 实现将实体对象转换成json对象
*/
public String obj2JsonData(Student student) {
String jsonData = null;
try {
// 使用XContentBuilder创建json数据
XContentBuilder jsonBuild = XContentFactory.jsonBuilder();
jsonBuild.startObject().field("sId", student.getsId())
.field("sName", student.getsName())
.field("sAge", student.getsAge()).endObject();
jsonData = jsonBuild.string();
System.out.println(jsonData);
} catch (IOException e) {
e.printStackTrace();
}
return jsonData;
}
public List<String> getInitJsonData() {
List<String> list = new ArrayList<String>();
String s1 = this.obj2JsonData(new Student(7, "龚秋霞", "22"));
String s2 = this.obj2JsonData(new Student(8, "夏静思", "23"));
list.add(s1);
list.add(s2);
return list;
}
/**
* 初始化客户端连接
*/
@Before
public void initESClient() {
// 配置你的es,现在这里只配置了集群的名,默认是elasticsearch,跟服务器的相同
Settings settings = ImmutableSettings.settingsBuilder()
.put("cluster.name", "elasticsearch").build();
// 这里可以同时连接集群的服务器,可以多个,并且连接服务是可访问的
client = new TransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(
"127.0.0.1", 9300));
}
@After
public void closeESClient() {
client.close();
}
private Client client;
}
package org.dennisit.elastic.process;
import java.util.ArrayList;
import java.util.List;
import org.dennisit.entity.Student;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* 通过条件查询
* @author 高国藩
* @date 2015年6月12日 下午8:00:43
*
*/
public class Serch {
private static final String type = "st_tb";
private static final String indexname = "st_in";
@Test
public void serch(){
List<Student> list = new ArrayList<Student>();
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("sName", "康"));
SearchResponse searchResponse = client.prepareSearch(indexname)
.setTypes(type).setQuery(queryBuilder).execute().actionGet();
SearchHits hits = searchResponse.getHits();
System.out.println("查询到记录数=" + hits.getTotalHits());
SearchHit[] searchHists = hits.getHits();
if (searchHists.length > 0) {
for (SearchHit hit : searchHists) {
Integer id = (Integer) hit.getSource().get("sId");
String name = (String) hit.getSource().get("sName");
String function = (String) hit.getSource().get("sAge");
list.add(new Student(id, name, function));
}
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).toString());
}
}
/**
* 初始化客户端连接
*/
@Before
public void initESClient() {
// 配置你的es,现在这里只配置了集群的名,默认是elasticsearch,跟服务器的相同
Settings settings = ImmutableSettings.settingsBuilder().put("cluster.name", "elasticsearch").build();
// 这里可以同时连接集群的服务器,可以多个,并且连接服务是可访问的
client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));
}
@After
public void closeESClient() {
client.close();
}
private Client client;
}
package org.dennisit.elastic.process;
import java.io.IOException;
import java.util.List;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.junit.Test;
/**
* 批量增加
* @author 高国藩
* @date 2015年6月12日 下午6:37:16
*
*/
public class Buil {
ElasticSearchHandler esHandler = new ElasticSearchHandler();
/**
* 使用bulk一次请求建立200万条索引记录
*/
@Test
public void bulkIndex() {
long start = System.currentTimeMillis();
BulkRequestBuilder bulkRequestBuilder = esHandler.getClient().prepareBulk();
for (int i = 0; i < 20; i++) {
String id = "id" + i;
String title = "this is title " + i;
bulkRequestBuilder.add(this.getIndexRequestBuilder(id, title));
}
System.out.println("start build index");
bulkRequestBuilder.execute().actionGet();
System.out.println(System.currentTimeMillis() - start);
}
/**
* 返回一个索引请求builder
*
* @param id
* @param title
* @return
*/
private IndexRequestBuilder getIndexRequestBuilder(String id, String title) {
return esHandler.getClient().prepareIndex("test1", "test11").setSource(this.getBuilderJson(id, title));
}
/**
* 创建索引 通常是json格式
*
* @param obj
* 创建索引的实体
*
* @return
*/
private String getBuilderJson(String id, String title) {
String json = "";
try {
XContentBuilder contentBuilder = XContentFactory.jsonBuilder().startObject();
contentBuilder.field("id", id);
contentBuilder.field("title", title);
json = contentBuilder.endObject().string();
} catch (IOException e) {
e.printStackTrace();
}
return json;
}
}
package org.dennisit.elastic.process;
import java.util.Map;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
*
* 删除数据 根据自定义插入的id来删除数据
*
* @author oyhk
*
*/
public class Delete {
private static final String type = "st_tb";
private static final String indexname = "st_in";
@Test
public void delete() {
DeleteResponse response = client.prepareDelete(indexname, type, "123456").execute().actionGet();
// 下面是不在多线程操作,他默认为.setOperationThreaded(true)
// DeleteResponse response = client.prepareDelete("twitter", "tweet","1").setOperationThreaded(false).execute().actionGet();
boolean isNotFound = response.isFound();
System.out.println(isNotFound); // 返回索引是否存在,存在删除
Map headers = (Map) response.getHeaders();
System.out.println(headers);// 返回响应头
// 其它的也没什么好写了...
}
@Test
public void get() {
GetResponse response = client.prepareGet("test1", "test11", "w_NtEKMGQRSkKgXF8aZBfA").execute().actionGet();
// 下面是不在多线程操作,他默认为.setOperationThreaded(true)
// GetResponse response = client.prepareGet("twitter", "tweet","1").setOperationThreaded(false).execute().actionGet();
Map headers = (Map) response.getHeaders();
System.out.println(headers);// 获取请求头
boolean exists = response.isExists();
System.out.println(exists);// 判断索引是否存在
String sourceString = response.getSourceAsString();
System.out.println(sourceString);// 获取索引,并且打印出索引内容
String id = response.getId();
System.out.println(id);// 获取索引id
boolean sourceEmpty = response.isSourceEmpty();
System.out.println(sourceEmpty);// 获取索引的内容是否为空,下面还有一些方法,我没有一一列举出来,大家可以试试
}
@Test
public void search() {
// 创建查询索引
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("test1");
// 设置查询索引类型
searchRequestBuilder.setTypes("post");
// 设置查询类型
// 1.SearchType.DFS_QUERY_THEN_FETCH = 精确查询
// 2.SearchType.SCAN = 扫描查询,无序
// 3.SearchType.COUNT = 不设置的话,这个为默认值,还有的自己去试试吧
searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
// 设置查询关键词
// fieldQuery 这个必须是你的索引字段哦,不然查不到数据,这里我只设置两个字段 id ,title
searchRequestBuilder.setQuery(QueryBuilders.fuzzyQuery("test1", "test11"));
// 设置查询数据的位置,分页用吧
searchRequestBuilder.setFrom(0);
// 设置查询结果集的最大条数
searchRequestBuilder.setSize(60);
// 设置是否按查询匹配度排序
searchRequestBuilder.setExplain(true);
// 最后就是返回搜索响应信息
SearchResponse response = searchRequestBuilder.execute().actionGet();
SearchHits searchHits = response.getHits();
SearchHit[] hits = searchHits.getHits();
for (int i = 0; i < hits.length; i++) {
SearchHit hit = hits[i];
Map result = hit.getSource();
System.out.println(result);
}
System.out.println("search success ..");
}
/**
* 初始化客户端连接
*/
@Before
public void initESClient() {
// 配置你的es,现在这里只配置了集群的名,默认是elasticsearch,跟服务器的相同
Settings settings = ImmutableSettings.settingsBuilder().put("cluster.name", "elasticsearch").build();
// 这里可以同时连接集群的服务器,可以多个,并且连接服务是可访问的
client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));
}
@After
public void closeESClient() {
client.close();
}
private Client client;
}