1. ElasticSearch
1.1 ElasticSearch的簡(jiǎn)單介紹
ElasticSearch 是開(kāi)源搜索平臺(tái)領(lǐng)域的一個(gè)新成員辜昵。 ElasticSearch(簡(jiǎn)稱 ES) 是一個(gè)基于 Lucene 構(gòu)建的開(kāi)源难菌,分布式泽论,RESTful 搜索引擎。 具有搜索實(shí)時(shí)甚侣、穩(wěn)定福压、可靠和快速的特點(diǎn),并且安裝使用方便疯特。 支持通過(guò) HTTP 請(qǐng)求哗魂,使用 JSON 進(jìn)行數(shù)據(jù)索引肛走。
1.2 ElasticSearch的一些概念的介紹
(1). 索引: 一個(gè)索引就是一個(gè)擁有幾分相似特征的文檔的集合。一個(gè)索引由一個(gè)名字來(lái)標(biāo)識(shí)(必須全部是小寫(xiě)字母的)录别,并且當(dāng)我們要對(duì)對(duì)應(yīng)于這個(gè)索引中的文檔進(jìn)行索引朽色、搜索邻吞、更新和刪除的時(shí)候,都要使用到這個(gè)名字葫男。在一個(gè)集群中抱冷,可以定義任意多的索引。索引名稱必須要全部小寫(xiě)梢褐,也不能以下劃線開(kāi)頭旺遮,不能包含逗號(hào)。類似于關(guān)系型數(shù)據(jù)庫(kù)中的數(shù)據(jù)庫(kù)盈咳;
(2). 類型:在一個(gè)索引中耿眉,可以定義一種或多種類型。一個(gè)類型是你的索引的一個(gè)邏輯上的分類/分區(qū),通常鱼响,會(huì)為具有一組共同字段的文檔定義一個(gè)類型鸣剪,每一個(gè)類型都擁有自己的映射(mapping)或者結(jié)構(gòu)定義,它們定義了當(dāng)前類型下的數(shù)據(jù)結(jié)構(gòu)丈积,類似于數(shù)據(jù)庫(kù)表中的列筐骇。劃分時(shí)需要注意一些限制條件,例如不同的文檔類型對(duì)同一字段不能設(shè)置為不同的字段類型;類似于關(guān)系型數(shù)據(jù)庫(kù)中的的表江滨;
(3). 文檔:一個(gè)文檔是一個(gè)可被索引的基礎(chǔ)信息單元铛纬。文檔以JSON(JavascriptObject Notation)格式來(lái)表示,一個(gè)文檔不只包含了數(shù)據(jù)牙寞。它還包含了元數(shù)據(jù)(metadata) —— 關(guān)于文檔的信息饺鹃。有三個(gè)元數(shù)據(jù)元素是必須存在的,它們是:id是一個(gè)字符串间雀, _index 和 _type 悔详,他們可以組合起來(lái)鎖定Elasticsearch中一個(gè)特定的文檔。
1.3 ElasticSearch與關(guān)系型數(shù)據(jù)庫(kù)的對(duì)照關(guān)系
DB -> Databases -> Tables -> Rows -> Columns
ES -> Indices -> Types -> Documents -> Fields
3.4 ElasticSearch中對(duì)索引的一些常用操作
1. 獲取Elasticsearch中所有的index:
curl -XGET 'localhost:9200/_cat/indices?v&pretty'
2. 獲取某索引下所有的type:
獲取elasticsearch索引下所有的type定義
curl -XGET 'localhost:9200/elasticsearch/_mapping'
3. 刪除索引:
刪除elasticsearch1索引
curl -XDELETE 'localhost:9200/elasticsearch1?pretty'
4. 刪除某索引下的某type數(shù)據(jù):
刪除索引elasticsearch下的article類型
curl -XDELETE 'http://localhost:9200/elasticsearch/article/'
5. 查看某索引的某type下所有的數(shù)據(jù):
查找elasticsearch索引中所有的類型為Company的數(shù)據(jù)
http://localhost:9200/elasticsearch/Company/_search
3.5 ElasticSearch所遇到過(guò)的問(wèn)題
1 當(dāng)查詢的時(shí)候如果沒(méi)有設(shè)置from和size惹挟,那么默認(rèn)只會(huì)查出10條茄螃,不是我們想要的果
解決辦法: 通過(guò)先查出總的條數(shù),再將其值設(shè)置為size连锯;
2 查詢多條數(shù)據(jù)時(shí)遇到過(guò)的問(wèn)題:
錯(cuò)誤提示信息:Result window is too large
解決方案: 主要是修改index.max_result_window參數(shù)归苍,默認(rèn)為10000
命令:curl -XPUT http://127.0.0.1:9200/cmdb-now/_settings -d '{ "index" : { "max_result_window" : 100000000}}'
3 各種版本與api不匹配的問(wèn)題
解決方式:上網(wǎng)找,以及測(cè)試api與版本
1.6 ElasticSearch架構(gòu)及其支持的客戶端連接方式
方式一:REST API 运怖,端口 9200:這種連接方式對(duì)應(yīng)于架構(gòu)圖中的RESTful style API這一層拼弃,這種客戶端的連接方式是RESTful風(fēng)格的,使用http的方式進(jìn)行連接
方式二:Transport 摇展,端口 9300:這種連接方式對(duì)應(yīng)于架構(gòu)圖中的Transport這一層吻氧,這種客戶端連接方式是直接連接ES的節(jié)點(diǎn),使用TCP的方式進(jìn)行連接;(ES7.0將會(huì)關(guān)閉Transport,8.0將完全刪除盯孙,取而代之的是High Level REST Client)
ElasticSearch提供了兩個(gè)JAVA REST client 版本:
Java Low Level REST Client: 低級(jí)別的REST客戶端鲁森,通過(guò)http與集群交互,需自己編組請(qǐng)求JSON串振惰,及解析響應(yīng)JSON串歌溉。兼容所有ES版本。Java High Level REST Client: 高級(jí)別的REST客戶端骑晶,基于低級(jí)別的REST客戶端痛垛,增加了編組請(qǐng)求JSON串、解析響應(yīng)JSON串等相關(guān)api桶蛔。使用的版本需要保持和ES服務(wù)端的版本一致榜晦,否則會(huì)有版本問(wèn)題。
1.7 代碼示例
/**
* @description: es工具類
* @author: Guimu
* @create: 2018/07/31 11:47:55
**/
@Component
public class EsUtils {
@Autowired
private RestHighLevelClient client;
private static final String CURRENT_MODEL_PACKAGE_NAME = "com.yy.elasticsearch.model.";
private static final String DEFAULT_INDEX = "elasticsearch";
/**
* @Description: 根據(jù)Base 子類數(shù)據(jù)產(chǎn)生一個(gè)IndexRequest數(shù)據(jù)
* @Param: [source]
* @Return: org.elasticsearch.action.index.IndexRequest
* @Author: Guimu
* @Date: 2018/7/31 下午5:30
*/
private IndexRequest indexRequestGenerater(Base source) {
IndexRequest indexRequest = null;
if (StringUtils.isEmpty(source.getIndex())) {
source.setIndex(DEFAULT_INDEX);
}
try {
String[] tempArr = source.getClass().getName().split("\\.");
source.setType(tempArr[tempArr.length - 1]);
indexRequest = new IndexRequest(source.getIndex(), source.getType());
indexRequest.source(JacksonUtil.getString(source), XContentType.JSON);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return indexRequest;
}
/**
* @Description: 批量存儲(chǔ)接口, boolean 表示保存成功與否
* @Param: [bases]
* @Return: boolean
* @Author: Guimu
* @Date: 2018/7/31 下午5:32
*/
public boolean batchSave(List<? extends Base> bases) {
BulkRequest bulkRequest = new BulkRequest();
bases.forEach(el -> bulkRequest.add(indexRequestGenerater(el)));
boolean flag = false;
try {
BulkResponse bulkItemResponses = client.bulk(bulkRequest);
flag = "created".equalsIgnoreCase(bulkItemResponses.getItems()[0].getResponse().getResult().name());
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
/**
* @Description: 保存單個(gè)索引文檔數(shù)據(jù)
* @Param: [source]
* @Return: boolean
* @Author: Guimu
* @Date: 2018/7/31 下午2:05
*/
public boolean singleSave(Base source) {
IndexRequest singleRequest;
boolean flag = false;
try {
singleRequest = indexRequestGenerater(source);
IndexResponse indexResponse = client.index(singleRequest);
flag = "created".equalsIgnoreCase(indexResponse.getResult().name());
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
/**
* @Description: 模糊匹配名字, 精確匹配corpId
* @Param: [name, corpId]
* @Return: java.util.List<com.yy.elasticsearch.model.Base>
* @Author: Guimu
* @Date: 2018/7/31 下午2:21
*/
public List<Base> queryLikeNameAndCorpId(String name, String type, Long corpId) {
MatchPhraseQueryBuilder mb1 = QueryBuilders.matchPhraseQuery("corpId", corpId);
MatchPhraseQueryBuilder mb2 = QueryBuilders.matchPhraseQuery("name", "*" + name + "*");
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(mb1).must(mb2);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest(DEFAULT_INDEX);
searchRequest.types(type);
searchRequest.source(searchSourceBuilder);
return baseQuery(searchRequest);
}
/**
* @Description: 查找指定corpId和type的所有數(shù)據(jù)
* @Param: [name, corpId]
* @Return: java.util.List<com.yy.elasticsearch.model.Base>
* @Author: Guimu
* @Date: 2018/7/31 下午2:21
*/
public List<Base> queryByCorpId(String type, Long corpId) {
MatchPhraseQueryBuilder mb = QueryBuilders.matchPhraseQuery("corpId", corpId);
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(mb);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest(DEFAULT_INDEX);
searchRequest.types(type);
searchRequest.source(searchSourceBuilder);
return baseQuery(searchRequest);
}
/**
* @Description: 查詢?cè)撍饕? 指定type的所有數(shù)據(jù)
* @Param: [index, type]
* @Return: java.util.List<com.yy.elasticsearch.model.Base>
* @Author: Guimu
* @Date: 2018/7/31 下午6:06
*/
public List<Base> findAll(String index, String type) {
SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(this.getCount(searchRequest).intValue());
searchRequest.source(searchSourceBuilder);
//查詢?nèi)縳xxxx
searchRequest.types(type);
return baseQuery(searchRequest);
}
/**
* @Description: 獲取該查詢請(qǐng)求的總條數(shù)total
* @Param: [searchRequest]
* @Return: java.lang.Long
* @Author: Guimu
* @Date: 2018/7/31 下午4:58
*/
private Long getCount(SearchRequest searchRequest) {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(1);
searchRequest.source(searchSourceBuilder);
try {
SearchResponse response = client.search(searchRequest);
return response.getHits().getTotalHits();
} catch (IOException e) {
e.printStackTrace();
}
return -1L;
}
/**
* @Description: 私有的基礎(chǔ)查詢, 提高代碼復(fù)用性
* @Param: [searchRequest]
* @Return: java.util.List<com.yy.elasticsearch.model.Base>
* @Author: Guimu
* @Date: 2018/7/31 下午6:15
*/
private List<Base> baseQuery(SearchRequest searchRequest) {
try {
SearchResponse response = client.search(searchRequest);
return Arrays.asList(response.getHits().getHits()).stream().map(el -> {
Map<String, Object> map = el.getSource();
Class clazz;
Base base = null;
try {
map.put("id", el.getId());
clazz = Class.forName(CURRENT_MODEL_PACKAGE_NAME + map.get("type").toString());
base = (Base) JacksonUtil.getObject(JacksonUtil.getString(map), clazz);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return base;
}).collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* @Description: 基礎(chǔ)刪除接口, 支持Base的所有子類
* @Param: [base]
* @Return: boolean
* @Author: Guimu
* @Date: 2018/7/31 下午6:32
*/
public boolean deleteBase(Base base) {
DeleteRequest deleteRequest = new DeleteRequest(base.getIndex(), base.getType(), base.getId());
boolean flag = false;
try {
DeleteResponse deleteResponse = client.delete(deleteRequest);
flag = "deleted".equalsIgnoreCase(deleteResponse.getResult().name());
System.out.println(deleteResponse);
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
/**
* @Description: 此處傳入的base的所有值都是全的羽圃,沒(méi)有null值
* @Param: [base]
* @Return: boolean
* @Author: Guimu
* @Date: 2018/8/1 上午10:02
*/
public boolean updateBase(Base base) {
UpdateRequest updateRequest = new UpdateRequest(base.getIndex(), base.getType(), base.getId());
boolean flag = false;
try {
updateRequest.doc(JacksonUtil.getString(base), XContentType.JSON);
UpdateResponse updateResponse = client.update(updateRequest);
flag = "updated".equalsIgnoreCase(updateResponse.getResult().name());
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
/**
* @Description: 根據(jù)名字, type, corpId 進(jìn)行精確查詢Base數(shù)據(jù),沒(méi)找到則返回 null
* @Param: [name, type, corpId]
* @Return: com.yy.elasticsearch.model.Base
* @Author: Guimu
* @Date: 2018/8/1 上午9:35
*/
public <T extends Base> T queryOneBase(String name, String type, Long corpId) {
MatchPhraseQueryBuilder mb = QueryBuilders.matchPhraseQuery("corpId", corpId);
MatchPhraseQueryBuilder mb1 = QueryBuilders.matchPhraseQuery("name", name);
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(mb).must(mb1);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest(DEFAULT_INDEX);
searchRequest.types(type);
searchRequest.source(searchSourceBuilder);
Base rebase = null;
try {
rebase = baseQuery(searchRequest).get(0);
} catch (NullPointerException e) {
e.printStackTrace();
}
Class<T> aClass = null;
try {
aClass = (Class<T>) Class.forName(CURRENT_MODEL_PACKAGE_NAME + type);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null == rebase ? null : aClass.cast(rebase);
}
public static String getDefaultIndex() {
return DEFAULT_INDEX;
}
}