1.在spring原有及基础上新增Maven依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.3.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.3.2</version>
</dependency>
2.ES 配置参数
创建 ElasticSearchProperties类
@ConfigurationProperties(prefix = "com.commons.es")
public class ElasticSearchProperties {
private String host = "localhost";
private int port = 9200;
private String schema = "http";
private int connectTimeOut = 1000;
private int socketTimeOut = 30000;
private int connectionRequestTimeOut = 500;
private int maxConnectNum = 100;
private int maxConnectPerRoute = 100;
private boolean uniqueConnectTimeConfig = true;
private boolean uniqueConnectNumConfig = true;
private Integer shades = 3;//分片数
private Integer replicas = 2;//副本数
}
3.ES Java客户端连接
创建ElasticSearchAutoConfig类
@Configuration
//可根据自己所在的目录要扫描的参数,如下图
@ComponentScan(basePackages = "com.manager.commons.es")
@EnableConfigurationProperties(ElasticSearchProperties.class)
public class ElasticSearchAutoConfig {
private HttpHost httpHost;
private RestClientBuilder builder;
private RestHighLevelClient client;
@Autowired
private ElasticSearchProperties elasticSearchProperties;
@Bean
public RestHighLevelClient restHighLevelClient() {
httpHost = new HttpHost(elasticSearchProperties.getHost(), elasticSearchProperties.getPort(), elasticSearchProperties.getSchema());
builder = RestClient.builder(httpHost);
if (elasticSearchProperties.isUniqueConnectTimeConfig()) {
setConnectTimeOutConfig();
}
if (elasticSearchProperties.isUniqueConnectNumConfig()) {
setMutiConnectConfig();
}
client = new RestHighLevelClient(builder);
return client;
}
/**
* 异步httpclient的连接延时配置
*/
public void setConnectTimeOutConfig() {
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(elasticSearchProperties.getConnectTimeOut());
requestConfigBuilder.setSocketTimeout(elasticSearchProperties.getSocketTimeOut());
requestConfigBuilder.setConnectionRequestTimeout(elasticSearchProperties.getConnectionRequestTimeOut());
return requestConfigBuilder;
});
}
/**
* 异步httpclient的连接数配置
*/
public void setMutiConnectConfig() {
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(elasticSearchProperties.getMaxConnectNum());
httpClientBuilder.setMaxConnPerRoute(elasticSearchProperties.getMaxConnectPerRoute());
return httpClientBuilder;
});
}
/**
* 关闭连接
*/
public void close() {
if (client != null) {
try {
client.close();
} catch (IOException e) {
log.error("es close error", e);
}
}
}
}
4.创建索引并验证结果
/**
* 数据类型
*
* @author CHANG
* @date 2019/7/21 14:43
*/
public interface DailyEsEntity {
Map<String, Object> genInitMap();
Map<String, String> DATE_MAP = Collections.unmodifiableMap(new HashMap() {
{
put("type", "date");
}
});
Map<String, String> LONG_MAP = Collections.unmodifiableMap(new HashMap() {
{
put("type", "long");
}
});
Map<String, String> KEYWORD_MAP = Collections.unmodifiableMap(new HashMap() {
{
put("type", "keyword");
}
});
Map<String, String> INTEGER_MAP = Collections.unmodifiableMap(new HashMap() {
{
put("type", "integer");
}
});
Map<String, String> BOOLEAN_MAP = Collections.unmodifiableMap(new HashMap() {
{
put("type", "boolean");
}
});
Map<String, String> TEXT_MAP = Collections.unmodifiableMap(new HashMap() {
{
put("type", "text");
}
});
}
/**
*自定义注解标识文档
* @author Chang
* @date 2019/3/27 14:09
*/
@Qualifier
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ESDocument {
/**
* 标识文档
* @return indexName
*/
String indexName();
/**
*是否是文档
* @return boolean
*/
boolean dailyIndex() default false;
}
/**
*es文档mapping及类型
* @author CHANG
* @date 2019/7/21 14:34
*/
@Data
@ESDocument(indexName = "user_result", dailyIndex = true)
public class User implements DailyEsEntity {
public static final String USER_INDEX = "user_result";
private Long id;
private String name;
private Integer age;
private Boolean isDelete;
private Data createTime;
@Override
public Map<String, Object> genInitMap() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", LONG_MAP);
map.put("name", KEYWORD_MAP);
map.put("age", INTEGER_MAP);
map.put("isDelete", BOOLEAN_MAP);
map.put("createTime", DATE_MAP);
return map;
}
}
/**
* es索引创建
* @author CHANG
* @date 2019/7/21 15:01
*/
@Slf4j
public class ESInitManager {
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private ElasticSearchProperties elasticSearchProperties;
/**
* 判断index是否存在
*
* @param index index
* @return indexExists 判断索引是否存在
* @throws Exception ex
*/
boolean indexExists(String index) throws Exception {
GetIndexRequest request = new GetIndexRequest();
request.indices(index);
request.local(false);
request.humanReadable(true);
boolean exists = restHighLevelClient.indices().exists(request);
return exists;
}
/**
* 创建索引
*
* @param index 索引
* @param indexType 类型
* @param properties indexType 数据类型
* @return boolean
*/
public boolean init(String index, String indexType, Map<String, Object> properties) {
try {
log.info("init {}", index);
if (indexExists(index)) {
return true;
}
CreateIndexRequest request = new CreateIndexRequest(index);
request.settings(Settings.builder()
.put("index.number_of_shards", elasticSearchProperties.getShades())
.put("index.number_of_replicas", elasticSearchProperties.getReplicas())); //副本数
Map<String, Object> jsonMap = new HashMap<>();
Map<String, Object> mapping = new HashMap<>();
mapping.put("properties", properties);
jsonMap.put(indexType, mapping);
request.mapping(indexType, jsonMap);
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request);
boolean acknowledged = createIndexResponse.isAcknowledged();
log.info("CreateIndexResponse " + acknowledged);
return acknowledged;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
/**
* @author CHANG
* @date 2019/7/21 15:14
*/
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@Slf4j
public class ESInitManagerTest {
@Autowired
private ESInitManager esInitManager;
/**
* 这里我采用索引与类型的名字一样可根据自己的需求改变名称
*/
@Test
public void init() {
User user = new User();
boolean init = esInitManager.init(user.USER_INDEX, user.USER_INDEX, user.genInitMap());
log.info("init {}", init);
}
}
5.es单节点创建索引副本为分配的问题
上面截图可以看出存在3个unassigned的分片,新建索引user_result的时候,分片数为3,副本数为2,新建之后集群状态成为yellow,其根本原因是因为集群存在没有启用的副本分片。
副本分片的主要目的就是为了故障转移,如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色。
那么可以看出来副本分片和主分片是不能放到一个节点上面的,可是在只有一个节点的集群里,副本分片没有办法分配到其他的节点上,所以出现所有副本分片都unassigned得情况。
因为只有一个节点,如果存在主分片节点挂掉了,那么整个集群理应就挂掉了,不存在副本分片升为主分片的情况。
解决办法就是,在单节点的elasticsearch集群,删除存在副本分片的索引,新建索引的副本都设为0。然后再查看集群状态
//修改副本数
@ConfigurationProperties(prefix = "com.commons.es")
public class ElasticSearchProperties {
private String host = "localhost";
private int port = 9200;
private String schema = "http";
private int connectTimeOut = 1000;
private int socketTimeOut = 30000;
private int connectionRequestTimeOut = 500;
private int maxConnectNum = 100;
private int maxConnectPerRoute = 100;
private boolean uniqueConnectTimeConfig = true;
private boolean uniqueConnectNumConfig = true;
private Integer shades = 3;//分片数
private Integer replicas = 0;//副本数
}