鏈接上一篇文章 :ES快速入門 http://www.reibang.com/p/7d687c9dba4f
6索引管理
6.1 搭建工程
6.1.1 ES客戶端
ES提供多種不同的客戶端:
1、TransportClient
ES提供的傳統(tǒng)客戶端,官方計(jì)劃8.0版本刪除此客戶端逊脯。
2拗秘、RestClient
RestClient是官方推薦使用的碗啄,它包括兩種:Java Low Level REST Client和 Java High Level REST Client碘菜。
ES在6.0之后提供 Java High Level REST Client, 兩種客戶端官方更推薦使用 Java High Level REST Client振峻,不過當(dāng)前它還處于完善中,有些功能還沒有择份。
我們準(zhǔn)備采用 Java High Level REST Client扣孟,如果它有不支持的功能,則使用Java Low Level REST Client荣赶。
1凤价、添加依賴:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch‐rest‐high‐level‐client</artifactId>
<version>6.2.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.2.1</version>
</dependency>
2、配置文件
server:
port: ${port:40100}
spring:
application:
name: xc-search-service
xuecheng:
elasticsearch:
hostlist: ${eshostlist:127.0.0.1:9200} #多個(gè)結(jié)點(diǎn)中間用逗號(hào)分隔
3拔创、配置類
@Configuration
public class ElasticsearchConfig {
@Value("${xuecheng.elasticsearch.hostlist}")
private String hostlist;
@Bean
public RestHighLevelClient restHighLevelClient(){
//解析hostlist配置信息
String[] split = hostlist.split(",");
//創(chuàng)建HttpHost數(shù)組佛吓,其中存放es主機(jī)和端口的配置信息
HttpHost[] httpHostArray = new HttpHost[split.length];
for(int i=0;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
}
//創(chuàng)建RestHighLevelClient客戶端
return new RestHighLevelClient(RestClient.builder(httpHostArray));
}
//項(xiàng)目主要使用RestHighLevelClient,對(duì)于低級(jí)的客戶端暫時(shí)不用
@Bean
public RestClient restClient(){
//解析hostlist配置信息
String[] split = hostlist.split(",");
//創(chuàng)建HttpHost數(shù)組眷细,其中存放es主機(jī)和端口的配置信息
HttpHost[] httpHostArray = new HttpHost[split.length];
for(int i=0;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
}
return RestClient.builder(httpHostArray).build();
}
}
6.2創(chuàng)建索引庫(kù)
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestSearch {
@Autowired
RestHighLevelClient restHighLevelClient;
@Autowired
RestClient restClient;
@Test
public void creatIndex() throws IOException {
//創(chuàng)建索引請(qǐng)求對(duì)象
CreateIndexRequest createIndexRequest = new CreateIndexRequest("xc_course");
//設(shè)置索引參數(shù)
createIndexRequest.settings(Settings.builder().put("number_of_shards",1).put("number_of_replicas",0));
//設(shè)置映射
createIndexRequest.mapping("doc","{\n" +
"\"properties\": {\n" +
"\"name\": {\n" +
"\"type\": \"text\",\n" +
"\"analyzer\":\"ik_max_word\",\n" +
"\"search_analyzer\":\"ik_smart\"\n" +
"},\n" +
"\"description\": {\n" +
"\"type\": \"text\",\n" +
"\"analyzer\":\"ik_max_word\",\n" +
"\"search_analyzer\":\"ik_smart\"\n" +
"},\n" +
"\"studymodel\": {\n" +
"\"type\": \"keyword\"\n" +
"},\n" +
"\"price\": {\n" +
"\"type\": \"float\"\n" +
"},\n" +
"\"timestamp\": {\n" +
"\"type\": \"date\",\n" +
"\"format\": \"yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd||epoch_millis\"\n" +
"}\n" +
"}\n" +
"}\n" ,XContentType.JSON);
//鏈接客戶端
IndicesClient client = restHighLevelClient.indices();
//創(chuàng)建響應(yīng)對(duì)象
CreateIndexResponse response = client.create(createIndexRequest);
//響應(yīng)
boolean acknowledged = response.isAcknowledged();
System.out.println(acknowledged);
}
@Test
public void delIndex() throws IOException {
//創(chuàng)建索引請(qǐng)求對(duì)象
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("xc_course");
//鏈接客戶端
IndicesClient client = restHighLevelClient.indices();
//刪除索引
DeleteIndexResponse delete = client.delete(deleteIndexRequest);
//響應(yīng)
boolean acknowledged = delete.isAcknowledged();
System.out.println(acknowledged);
}
}
6.3 添加文檔
@Test
public void addDoc() throws IOException {
//準(zhǔn)備json數(shù)據(jù)
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "spring cloud實(shí)戰(zhàn)");
jsonMap.put("description", "本課程主要從四個(gè)章節(jié)進(jìn)行講解: 1.微服務(wù)架構(gòu)入門 2.spring cloud 基礎(chǔ)入門 3.實(shí)戰(zhàn)Spring Boot 4.注冊(cè)中心eureka膛虫。");
jsonMap.put("studymodel", "201001");
SimpleDateFormat dateFormat =new SimpleDateFormat("yyyy‐MM‐dd HH:mm:ss");
jsonMap.put("timestamp", dateFormat.format(new Date()));
jsonMap.put("price", 5.6f);
//創(chuàng)建索引請(qǐng)求對(duì)象
IndexRequest indexRequest = new IndexRequest("xc_course","doc");
//指定索引添加文檔
indexRequest.source(jsonMap);
//鏈接客戶端
IndexResponse indexResponse = restHighLevelClient.index(indexRequest);
//獲取響應(yīng)結(jié)果
DocWriteResponse.Result result = indexResponse.getResult();
System.out.println(result);
}
6.4 查詢文檔
@Test
public void queryDoc() throws IOException {
GetRequest getRequest = new GetRequest("xc_course","doc","5W8t9WgBMHjTRj0U9GkF");
GetResponse getResponse = restHighLevelClient.get(getRequest);
boolean exists = getResponse.isExists();
Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
System.out.println(sourceAsMap);
}
7搜索管理
7.1 準(zhǔn)備環(huán)境
創(chuàng)建xc_course索引庫(kù)。
創(chuàng)建映射:
post:http://localhost:9200/xc_course/doc/_mapping
{
"properties": {
"description": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"pic":{
"type":"text",
"index":false
},
"price": {
"type": "float"
},
"studymodel": {
"type": "keyword"
},
"timestamp": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
初始化文檔:
http://localhost:9200/xc_course/doc/1
{
"name": "Bootstrap開發(fā)",
"description": "Bootstrap是由Twitter推出的一個(gè)前臺(tái)頁(yè)面開發(fā)框架躏吊,是一個(gè)非常流行的開發(fā)框架氛改,此框架集成了多種頁(yè)面效果。此開發(fā)框架包含了大量的CSS比伏、JS程序代碼胜卤,可以幫助開發(fā)者(尤其是不擅長(zhǎng)頁(yè)面開發(fā)的程序人員)輕松的實(shí)現(xiàn)一個(gè)不受瀏覽器限制的精美界面效果。",
"studymodel": "201002",
"price":38.6,
"timestamp":"2018-04-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
http://localhost:9200/xc_course/doc/2
{
"name": "java編程基礎(chǔ)",
"description": "java語(yǔ)言是世界第一編程語(yǔ)言赁项,在軟件開發(fā)領(lǐng)域使用人數(shù)最多葛躏。",
"studymodel": "201001",
"price":68.6,
"timestamp":"2018-03-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
http://localhost:9200/xc_course/doc/3
{
"name": "spring開發(fā)基礎(chǔ)",
"description": "spring 在java領(lǐng)域非常流行,java程序員都在用悠菜。",
"studymodel": "201001",
"price":88.6,
"timestamp":"2018-02-24 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}
7.3 DSL搜索
DSL(Domain Specific Language)是ES提出的基于json的搜索方式舰攒,在搜索時(shí)傳入特定的json格式的數(shù)據(jù)來完成不同的搜索需求。
DSL比URI搜索方式功能強(qiáng)大悔醋,在項(xiàng)目中建議使用DSL方式來完成搜索摩窃。
7.3.1 查詢所有文檔
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestSearch {
@Autowired
RestHighLevelClient restHighLevelClient;
@Autowired
RestClient restClient;
@Test
public void queryAll() throws IOException, ParseException {
//搜索請(qǐng)求對(duì)象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定類型
searchRequest.types("doc");
//搜索源構(gòu)建對(duì)象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//搜索方式
//matchAllQuery搜索全部
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
searchRequest.source(searchSourceBuilder);
//執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
SearchResponse searchResponse = restHighLevelClient.search(searchRequest);
//搜索結(jié)果
SearchHits hits = searchResponse.getHits();
//匹配到的總記錄數(shù)
long totalHits = hits.getTotalHits();
//得到匹配度高的文檔
SearchHit[] searchHits = hits.getHits();
//日期格式化對(duì)象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文檔的主鍵
String id = hit.getId();
//源文檔內(nèi)容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
//由于前邊設(shè)置了源文檔字段過慮,這時(shí)description是取不到的
String description = (String) sourceAsMap.get("description");
//學(xué)習(xí)模式
String studymodel = (String) sourceAsMap.get("studymodel");
//價(jià)格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
}
7.3.2 分頁(yè)查詢
ES支持分頁(yè)查詢猾愿,傳入兩個(gè)參數(shù):from和size鹦聪。
form:表示起始文檔的下標(biāo),從0開始蒂秘。
size:查詢的文檔數(shù)量泽本。
//分頁(yè)查詢
@Test
public void testSearchPage() throws IOException, ParseException {
//搜索請(qǐng)求對(duì)象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定類型
searchRequest.types("doc");
//搜索源構(gòu)建對(duì)象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//設(shè)置分頁(yè)參數(shù)
//頁(yè)碼
int page = 1;
//每頁(yè)記錄數(shù)
int size = 1;
//計(jì)算出記錄起始下標(biāo)
int from = (page-1)*size;
searchSourceBuilder.from(from);//起始記錄下標(biāo),從0開始
searchSourceBuilder.size(size);//每頁(yè)顯示的記錄數(shù)
//搜索方式
//matchAllQuery搜索全部
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段姻僧,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
searchRequest.source(searchSourceBuilder);
//執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
SearchResponse searchResponse = client.search(searchRequest);
//搜索結(jié)果
SearchHits hits = searchResponse.getHits();
//匹配到的總記錄數(shù)
long totalHits = hits.getTotalHits();
//得到匹配度高的文檔
SearchHit[] searchHits = hits.getHits();
//日期格式化對(duì)象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文檔的主鍵
String id = hit.getId();
//源文檔內(nèi)容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
//由于前邊設(shè)置了源文檔字段過慮规丽,這時(shí)description是取不到的
String description = (String) sourceAsMap.get("description");
//學(xué)習(xí)模式
String studymodel = (String) sourceAsMap.get("studymodel");
//價(jià)格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
7.3.3 Term Query
Term Query為精確查詢,在搜索時(shí)會(huì)整體匹配關(guān)鍵字段化,不再將關(guān)鍵字分詞
//TermQuery
@Test
public void testTermQuery() throws IOException, ParseException {
//搜索請(qǐng)求對(duì)象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定類型
searchRequest.types("doc");
//搜索源構(gòu)建對(duì)象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//設(shè)置分頁(yè)參數(shù)
//頁(yè)碼
int page = 1;
//每頁(yè)記錄數(shù)
int size = 1;
//計(jì)算出記錄起始下標(biāo)
int from = (page-1)*size;
searchSourceBuilder.from(from);//起始記錄下標(biāo)嘁捷,從0開始
searchSourceBuilder.size(size);//每頁(yè)顯示的記錄數(shù)
//搜索方式
//termQuery
searchSourceBuilder.query(QueryBuilders.termQuery("name","spring"));
//設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
searchRequest.source(searchSourceBuilder);
//執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
SearchResponse searchResponse = client.search(searchRequest);
//搜索結(jié)果
SearchHits hits = searchResponse.getHits();
//匹配到的總記錄數(shù)
long totalHits = hits.getTotalHits();
//得到匹配度高的文檔
SearchHit[] searchHits = hits.getHits();
//日期格式化對(duì)象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文檔的主鍵
String id = hit.getId();
//源文檔內(nèi)容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
//由于前邊設(shè)置了源文檔字段過慮显熏,這時(shí)description是取不到的
String description = (String) sourceAsMap.get("description");
//學(xué)習(xí)模式
String studymodel = (String) sourceAsMap.get("studymodel");
//價(jià)格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
7.3.4 根據(jù)id精確匹配
ES提供根據(jù)多個(gè)id值匹配的方法:
//根據(jù)id查詢
@Test
public void testTermQueryByIds() throws IOException, ParseException {
//搜索請(qǐng)求對(duì)象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定類型
searchRequest.types("doc");
//搜索源構(gòu)建對(duì)象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//搜索方式
//根據(jù)id查詢
//定義id
String[] ids = new String[]{"1","2"};
searchSourceBuilder.query(QueryBuilders.termsQuery("_id",ids));
//設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段雄嚣,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
searchRequest.source(searchSourceBuilder);
//執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
SearchResponse searchResponse = client.search(searchRequest);
//搜索結(jié)果
SearchHits hits = searchResponse.getHits();
//匹配到的總記錄數(shù)
long totalHits = hits.getTotalHits();
//得到匹配度高的文檔
SearchHit[] searchHits = hits.getHits();
//日期格式化對(duì)象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文檔的主鍵
String id = hit.getId();
//源文檔內(nèi)容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
//由于前邊設(shè)置了源文檔字段過慮,這時(shí)description是取不到的
String description = (String) sourceAsMap.get("description");
//學(xué)習(xí)模式
String studymodel = (String) sourceAsMap.get("studymodel");
//價(jià)格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
7.3.9 排序
可以在字段上添加一個(gè)或多個(gè)排序喘蟆,支持在keyword缓升、date、float等類型上添加蕴轨,text類型的字段上不允許添加排序港谊。
//Sort
@Test
public void testSort() throws IOException, ParseException {
//搜索請(qǐng)求對(duì)象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定類型
searchRequest.types("doc");
//搜索源構(gòu)建對(duì)象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//boolQuery搜索方式
//定義一個(gè)boolQuery
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//定義過慮器
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
//添加排序
searchSourceBuilder.sort("studymodel", SortOrder.DESC);
searchSourceBuilder.sort("price", SortOrder.ASC);
//設(shè)置源字段過慮,第一個(gè)參數(shù)結(jié)果集包括哪些字段,第二個(gè)參數(shù)表示結(jié)果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//向搜索請(qǐng)求對(duì)象中設(shè)置搜索源
searchRequest.source(searchSourceBuilder);
//執(zhí)行搜索,向ES發(fā)起http請(qǐng)求
SearchResponse searchResponse = client.search(searchRequest);
//搜索結(jié)果
SearchHits hits = searchResponse.getHits();
//匹配到的總記錄數(shù)
long totalHits = hits.getTotalHits();
//得到匹配度高的文檔
SearchHit[] searchHits = hits.getHits();
//日期格式化對(duì)象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文檔的主鍵
String id = hit.getId();
//源文檔內(nèi)容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
//由于前邊設(shè)置了源文檔字段過慮橙弱,這時(shí)description是取不到的
String description = (String) sourceAsMap.get("description");
//學(xué)習(xí)模式
String studymodel = (String) sourceAsMap.get("studymodel");
//價(jià)格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}