ElasticSearch-Java-SearchGuard連線和使用
阿新 • • 發佈:2018-12-18
Elasticsearch
主要是Elasticsearch使用searchguard後Java連線及安全驗證
安全驗證這部分大多選擇的Xpack,但Xpack收費當時就用了searchguard,但searchguard相關的文件很少,算是一點點去看官方文件解決。
1. searchGuard與ELK的結合
1.1 安全證書可以通過官方網站線上生成,填寫叢集節點資訊。郵件傳送後下載到本地。
1.2 金鑰證書生成後必須將DN配置到elasticsearch.yml中。
證書生成方式不同DN不同,要檢視DN確保正確(命令可百度檢視證書DN)。同時search guard配置檔案中要加入該DN賬戶給該DN以賬戶和許可權。
sg_internal_users.yml:
sg_roles_mapping.yml
3. 這裡兩個較好的部落格
https://www.jianshu.com/p/91faac8e18cf
https://blog.csdn.net/z1x2c34/article/details/77968955#commentBox
4. 證書檔案在ops/resource中
- CN=sgadmin-keystore.jks和truststore.jks。
- clientUtil類在/service/util註冊成bean.
5. 一些具體的es和安全外掛的api建議去官網看,較詳細。
6. 我會貼出我的相關配置檔案以及部分程式碼供以參考.
2. searchGuard與Java的結合-建立client
2.1. 當es安裝searchGuard後就不能直接建立client連線了
2.2. 首先需要把 truststore.jks和CN=sgadmin-keystore.jks放到專案中,建立連線時需讀取進行安全驗證(不通過賬戶密碼)
2.3. 其次在需要指定連線引數
Settings settings = Settings.builder() .put("searchguard.ssl.transport.enabled", true) .put("searchguard.ssl.transport.keystore_filepath",xxx) .put("searchguard.ssl.transport.truststore_filepath",xxx) .put("searchguard.ssl.transport.keystore_password", "xxx") .put("searchguard.ssl.transport.truststore_password", "xxx") .put("searchguard.ssl.http.keystore_password", "xxx") .put("searchguard.ssl.http.truststore_password", "xxx") .put("searchguard.ssl.transport.enforce_hostname_verification", false) .put("client.transport.ignore_cluster_name", true) .build();
這裡的password需要注意,具體值在你生成安全證書檔案中的ReadMe.md中。
在:
Common passwords
Truststore password: xxx
Admin keystore and private key password: xxx
3.匯入資料
3.1支援json格式匯入,我這裡是將Bean轉成json格式匯入
ObjectMapper mapper = new ObjectMapper();
try {
mapJackson = mapper.writeValueAsString(xcBean);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
3.2匯入時如果資料量較大,可以使用BulkRequestBuilder批量匯入
//指定index和type
BulkRequestBuilder bulkRequest = esClient.prepareBulk();
bulkRequest.add(esClient.prepareIndex("xingce", "xc").setSource(mapJackson, XContentType.JSON));
if (count % 500 == 0) {
bulkRequest.execute().actionGet();
//此處新建一個bulkRequest,類似於重置效果。避免重複提交
bulkRequest = esClient.prepareBulk();
}
4. 搜尋
4.1 具體搜尋API不再列出,百度即可,我使用的是bool+should
/**
* 拼接查詢條件
**/
public QueryBuilder getQb(EsPageRequestBean esPageRequestBean) {
//多條件設定
MatchQueryBuilder mpq1 = QueryBuilders
.matchQuery(ES_TITLE, esPageRequestBean.getQuery());
MatchQueryBuilder mpq2 = QueryBuilders
.matchQuery(ES_QUESTIONS, esPageRequestBean.getQuery());
MatchQueryBuilder mpq3 = QueryBuilders
.matchQuery(ES_MATERIALS, esPageRequestBean.getQuery());
QueryBuilder qb = QueryBuilders.boolQuery()
.should(mpq1)
.should(mpq2)
.should(mpq3);
return qb;
}
4.2 高亮顯示
/**
* 拼接高亮查詢
**/
public HighlightBuilder getHb() {
HighlightBuilder hiBuilder = new HighlightBuilder();
//這裡設定包含高亮關鍵字的標籤
hiBuilder.preTags("<mark>").postTags("</mark>");
//這裡fields中設定需要高亮顯示的查詢欄位,名字是Es中的欄位名
hiBuilder.field(ES_TITLE).field(ES_QUESTIONS).field(ES_MATERIALS);
return hiBuilder;
}
4.3 分頁
分頁有兩種,我這裡使用的from,size.不過第一次查詢獲取總數時建議不拿資料只取counts,.setSize(0):這樣提高速度也能避免浪費效能
//查詢建立
SearchRequestBuilder responseBuilder = esClient
.prepareSearch("interview").setTypes("iv");
//第一次查詢建立獲取總條數分頁使用
SearchResponse myResponse = responseBuilder
.setQuery(qb)
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setSize(0)
.setExplain(true).execute().actionGet();
//獲取總數
long counts = myResponse.getHits().totalHits;
4.4 建立查詢
//根據分頁資訊查詢
SearchResponse pageResponse = responseBuilder
.setQuery(qb)
.highlighter(hiBuilder)
.setFrom((esRequestBean.getPage() - 1) * esRequestBean.getPageSize()).setSize(esRequestBean.getPageSize())
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setExplain(true).execute().actionGet();
SearchHits pageHits = pageResponse.getHits();
//迴圈裝配bean
for (SearchHit searchHit : pageHits) {
Map source = searchHit.getSource();
HighlightField titleHighlight = searchHit.getHighlightFields().get(ES_TITLE);
HighlightField questionHighlight = searchHit.getHighlightFields().get(ES_QUESTIONS);
HighlightField materialsHighlight = searchHit.getHighlightFields().get(ES_MATERIALS);
//這裡將取出的json資料轉成bean再處理
YourBean yourBean = (YourBean) JSONObject.toBean(JSONObject.fromObject(source), YourBean.class, classMap);
.....
.....
}
4.4.1這裡的classMap注意,當某欄位資訊是巢狀型別時 需要設好接受該欄位的Map資訊
//對於巢狀陣列型別,從Es中讀取時需先反射定義好map
Map<String, Class> classMap = new HashMap<String, Class>();
classMap.put("es中欄位", 接收該欄位Bean.class);
5.原始碼
具體相關程式碼於本人GitHub:https://github.com/liyifan687/Elasticsearch