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;//副本數
}