一.創建maven工程
工程結構
pom添加如下依賴:
<properties>
<es-version>5.6.1</es-version>
</properties>
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${es-version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${es-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
</dependencies>
Article.java
public class Article {
private String atcId;
private String title;
private String content;
log4j2.xml
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"></PatternLayout>
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"></AppenderRef>
</Root>
</Loggers>
</Configuration>
二.測試API
2.1創建索引,刪除索引
@Test
public void esTest() throws UnknownHostException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name","my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
System.out.println("" + preBuiltTransportClient.toString());
//創建索引
preBuiltTransportClient.admin().indices().prepareCreate("blog").get();
//刪除索引
// preBuiltTransportClient.admin().indices().prepareDelete("blog").get();
//最後關閉客戶端
preBuiltTransportClient.close();
}
2.1插入文檔
1)json格式插入文檔
@Test
public void esTest() throws UnknownHostException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name","my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
//插入JSON文檔,沒有index會創建
Article article = new Article();
article.setAtcId("1");
article.setTitle("第一文");
article.setContent("瀏覽器查看http://sdafadf:9200/blog2");
String articleJson = JsonUtils.objectToJson(article);
//prepareIndex(index名,type名,documentId)
IndexResponse indexResponse = preBuiltTransportClient.prepareIndex("blog", "article", "1")
.setSource(articleJson, XContentType.JSON)
.get();
System.out.println("1" + indexResponse.getId()); //輸出 11
System.out.println("2" + indexResponse.getIndex()); //輸出 2blog
System.out.println("3" + indexResponse.getType()); //輸出 3article
System.out.println("4" + indexResponse.getResult()); //輸出 4CREATED
System.out.println("5" + indexResponse.getShardId()); //輸出 5[blog][1]
System.out.println("6" + indexResponse.getShardInfo()); //輸出 6ShardInfo{total=1, successful=1, failures=[]}
System.out.println("7" + indexResponse.getVersion()); //輸出 71
System.out.println("8" + indexResponse.getLocation(""));//輸出 8/blog/article/1?routing=
//最後關閉客戶端
preBuiltTransportClient.close();
}
2)以map形式插入文檔
@Test
public void esTest() throws UnknownHostException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name","my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
//map形式插入文檔
Map<String,Object> map = new HashMap<>();
map.put("atcId","2");
map.put("title","第二文");
map.put("content","ID:ffmkiejjmecolpfloofpjologoblkegm\n");
IndexResponse indexResponse2 = preBuiltTransportClient.prepareIndex("blog", "article", "2")
.setSource(map)
.get();
//最後關閉客戶端
preBuiltTransportClient.close();
}
3)以ES構建器方式插入
@Test
public void esTest() throws UnknownHostException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name","my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
//ES構建器形式插入文檔
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject()
.field("atcId", "3")
.field("title", "第3文")
.field("content", "頁面空白 報錯信息 此時頁面一片空白 報錯原因 Babel 默認只轉換")
.endObject();
IndexResponse indexResponse3 = preBuiltTransportClient.prepareIndex("blog", "article", "3")
.setSource(xContentBuilder)
.get();
//最後關閉客戶端
preBuiltTransportClient.close();
}
插入後效果:
2.2搜索文檔
1)獲取單條數據prepareGet(index名,type名,es唯一id)
@Test
public void esTest() throws IOException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name", "my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
//獲取數據
GetResponse getResponse = preBuiltTransportClient.prepareGet("blog", "article", "1").get();
System.out.println("獲取的數據爲:" + getResponse.getSourceAsString());//獲取的數據爲:{"atcId":"1","title":"第一文","content":"瀏覽器查看http://hadoop102:9200/blog2"}
//最後關閉客戶端
preBuiltTransportClient.close();
}
2)獲取多條數據
具體請看註釋:
@Test
public void esTest() throws IOException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name", "my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
//連續多個add一起寫,適用於獲取不同index,不同type的數據
MultiGetResponse multiGetItemResponses = preBuiltTransportClient.prepareMultiGet().add("blog", "article", "1").add("blog", "article", "2").get();
for (MultiGetItemResponse itemResponses : multiGetItemResponses) {
GetResponse getResponse = itemResponses.getResponse();
//如果真的存在,則打印
if (getResponse.isExists()) {
System.out.println("獲取的數據爲:" + getResponse.getSourceAsString());//
}
}
System.out.println("#########br###########");
//add()中要的id是一個不定長參數,可以一次性獲取多個id的document
//適用於獲取同一index,同一type的數據
MultiGetResponse multiGetItemResponses1 = preBuiltTransportClient.prepareMultiGet().add("blog", "article", "1", "2").get();
for (MultiGetItemResponse itemResponses : multiGetItemResponses1) {
GetResponse getResponse = itemResponses.getResponse();
//如果真的存在,則打印
if (getResponse.isExists()) {
System.out.println("獲取的數據爲:" + getResponse.getSourceAsString());//
}
}
//最後關閉客戶端
preBuiltTransportClient.close();
}
最終輸出爲:
獲取的數據爲:{"atcId":"1","title":"第一文","content":"瀏覽器查看http://hadoop102:9200/blog2"}
獲取的數據爲:{"atcId":"2","title":"第二文","content":"ID:ffmkiejjmecolpfloofpjologoblkegm\n"}
#########br###########
獲取的數據爲:{"atcId":"1","title":"第一文","content":"瀏覽器查看http://hadoop102:9200/blog2"}
獲取的數據爲:{"atcId":"2","title":"第二文","content":"ID:ffmkiejjmecolpfloofpjologoblkegm\n"}
2.3更新文檔
更新文檔的方式和插入文檔的神似,都是那幾種方式,如:
1)prepareUpdate的方式
@Test
public void esTest() throws IOException {
//獲取集羣信息
Settings settings = Settings.builder().put("cluster.name", "my-es-search").build();
//獲取客戶端
PreBuiltTransportClient preBuiltTransportClient = new PreBuiltTransportClient(settings);
//連接指定客戶端主機
preBuiltTransportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.1.117"), 9300));
//更新文檔
Map<String, Object> map = new HashMap<>();
map.put("title", "第一文-update文檔");
UpdateResponse updateResponse = preBuiltTransportClient.prepareUpdate("blog", "article", "1").setDoc(map).get();
System.out.println("" + updateResponse);//UpdateResponse[index=blog,type=article,id=1,version=2,result=updated,shards=ShardInfo{total=2, successful=1, failures=[]}]
//最後關閉客戶端
preBuiltTransportClient.close();
}
修改後的效果:
2)UpdateRequest的方式
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
Map<String, Object> map = new HashMap<>();
map.put("title", "第一文-第二次update文檔");
//UpdateRequest(String index, String type, String id)
preBuiltTransportClient.update(new UpdateRequest("blog", "article", "1")
.doc(map) //此處doc裏可以放json字符串, map,XContentBuilder.jsonBuilder IndexRequest等
).actionGet();
//##########關閉clien代碼###########
修改後的效果:
2.4 upsert文檔(更新插入)
這種方式是:存在修改,不存在則插入
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
Map<String, Object> map = new HashMap<>();
map.put("atcId", "8");
map.put("title", "update的文檔");
map.put("content", "This is update的文檔content");
Map<String, Object> mapUpsert = new HashMap<>();
mapUpsert.put("atcId", "8");
mapUpsert.put("title", "upsert的文檔");
mapUpsert.put("content", "This is upsert的文檔content");
preBuiltTransportClient.update(new UpdateRequest("blog", "article", "8")
//此處doc和upsert裏可以放json字符串, map,XContentBuilder.jsonBuilder IndexRequest等
//如果不存在插入mapUpsert的數據,否則修改成map的數據,執行2次可看效果
.doc(map).upsert(mapUpsert)
).actionGet();
//##########關閉clien代碼###########
第一次執行後的效果:(因爲id=8不存在,所以插入mapUpsert的數據)
第二次執行後的效果:(因爲id=8已存在,所以修改爲map的數據)
2.5 刪除文檔
刪除就是根據id刪除對應文檔
比如:這裏刪除id=2的文檔
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
DeleteResponse deleteResponse = preBuiltTransportClient.prepareDelete("blog", "article", "2").get();
//DeleteRequest的方式,差不多的操作方式
// DeleteResponse deleteResponse1 = preBuiltTransportClient.delete(new DeleteRequest("blog", "article", "2")).actionGet();
System.out.println("刪除結果:" + deleteResponse);
//刪除結果:DeleteResponse[index=blog,type=article,id=2,version=2,result=deleted,shards=ShardInfo{total=2, successful=1, failures=[]}]
//##########關閉clien代碼###########
刪除後,發現id=2的數據沒有了:
三.高級查詢
3.1 QueryBuilders.matchAllQuery() 查詢所有
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.matchAllQuery()).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//{"atcId":"8","title":"update的文檔","content":"This is update的文檔content"}
//{"atcId":"1","title":"第一文-第二次update文檔","content":"瀏覽器查看http://hadoop102:9200/blog2"}
//{"atcId":"3","title":"第3文","content":"頁面空白 報錯信息 此時頁面一片空白 報錯原因 Babel 默認只轉換"}
//##########關閉clien代碼###########
3.2 QueryBuilders.queryStringQuery(keyword) 根據所有字段分詞查詢
現在的數據裏只有id=1和id=8兩條數據裏有update關鍵字,且在不同的字段中,根據所有字段分詞查詢:在這裏是指既掃描title,又掃描content字段。所以這2個字段中包含update關鍵字的都會被查詢出來。
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
String keyword = "update";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.queryStringQuery(keyword)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:2
//{"atcId":"8","title":"update的文檔","content":"This is update的文檔content"}
//{"atcId":"1","title":"第一文-第二次update文檔","content":"瀏覽器查看http://hadoop102:9200/blog2"}
//##########關閉clien代碼###########
3.3 QueryBuilders.wildcardQuery(字段, 通配符關鍵字) 通配符查詢
------->可用的通配符有:
* :表示0個或多個字符
? :表示單個字符
1)星號通配符
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
String keywordLike = "*第*";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.wildcardQuery("title",keywordLike)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:2
//"atcId":"1","title":"第一文-第二次update文檔","content":"瀏覽器查看http://hadoop102:9200/blog2"}
//"atcId":"3","title":"第3文","content":"頁面空白 報錯信息 此時頁面一片空白 報錯原因 Babel 默認只轉換"}
//##########關閉clien代碼###########
2)問號通配符
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
String keywordLike = "第?";//?第
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.wildcardQuery("title",keywordLike)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:0
//這個是因爲默認的分詞器對中文的分詞效果很差,所以查詢不到數據,後面會介紹ik分詞器
//##########關閉clien代碼###########
3.4 QueryBuilders.termQuery(字段, 詞條關鍵字) 詞條查詢
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
String term = "第";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.termQuery("title",term)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:2
//"atcId":"1","title":"第一文-第二次update文檔","content":"瀏覽器查看http://hadoop102:9200/blog2"}
//"atcId":"3","title":"第3文","content":"頁面空白 報錯信息 此時頁面一片空白 報錯原因 Babel 默認只轉換"}
//##########關閉clien代碼###########
3.5 QueryBuilders.fuzzyQuery(字段, 關鍵字) 模糊查詢
這個區別於mysql的模糊查詢,mysql的模糊查詢和星號*通配符的方式類似的,es的模糊查詢是根據模糊程度查詢對應數據:
使用編輯距離的模糊查詢,計算量較大,但是對用戶拼寫錯的場景比較有用(如:模糊查詢4)
可以通過設置屬性來限定查詢的模糊程度:
1)指定最小相似度偏差: “min_similarity”:1
2) 模糊查詢將擴展到的默認最大數。默認值爲50:maxExpansions。
//##############此處獲取preBuiltTransportClient和上面代碼中的一樣哈,就不重複了,直接關鍵代碼##########
//模糊查詢1:Babel
String fuzzy = "Babel";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.fuzzyQuery("content",fuzzy)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:1
//"atcId":"3","title":"第3文","content":"頁面空白 報錯信息 此時頁面一片空白 報錯原因 Babel 默認只轉換"}
//模糊查詢2:babel(大小寫的轉換,全大寫BABEL是查詢不到的)
String fuzzy = "nabel";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.fuzzyQuery("content",fuzzy)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:1
//"atcId":"3","title":"第3文","content":"頁面空白 報錯信息 此時頁面一片空白 報錯原因 Babel 默認只轉換"}
//模糊查詢3:updat(去掉兩邊的其中1個字符)
String fuzzy = "updat";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.fuzzyQuery("content",fuzzy)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:1
//{"atcId":"8","title":"update的文檔","content":"This is update的文檔content"}
//模糊查詢4:upfate(寫錯一個字符)
String fuzzy = "upfate";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.fuzzyQuery("content",fuzzy)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:1
//{"atcId":"8","title":"update的文檔","content":"This is update的文檔content"}
//模糊查詢5:date(去掉2個字符)
String fuzzy = "upfate";
SearchResponse searchResponse = preBuiltTransportClient.prepareSearch("blog").setTypes("article")
.setQuery(QueryBuilders.fuzzyQuery("content",fuzzy)).get();
SearchHits searchHits = searchResponse.getHits();
System.out.println("查詢的總條數:" + searchHits.getTotalHits());//查詢的總條數:3
for (SearchHit searchHit : searchHits) {
System.out.println("" + searchHit.getSourceAsString());
}
//查詢的總條數:0
//##########關閉clien代碼###########
3.6 組合查詢
//---->: queryStringQuery會將關鍵字進行分詞,然後再對應列上進行查詢匹配,不指定對應列的,在所有列進行查詢
//---->: boolQuery:組合查詢,多條件一起查詢
//---->: must:必須條件 類似and
//---->: mustNot: 必須不條件
//---->: should: 可能含有,類似 or
//---->: filter:過濾,一般配合rangeQuery().from().to()使用
String[] isShowArr = {0,1};
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//這裏是查詢:顯示狀態是0,1,且商品名稱包含“蘋果”的商品。
boolQuery.must(QueryBuilders.termsQuery("isShow", isShowList)) //termsQuery傳集合,termQuery傳單個
.must(QueryBuilders.queryStringQuery("蘋果").field("productName"));
3.7 其他查詢
//範圍查詢,類似mysql的between and:查詢生日在("1990-01-01")到("1999-12-31")的
QueryBuilder qb = QueryBuilders.rangeQuery("birthday").from("1990-01-01").to("1999-12-31");
//前綴查詢:查詢姓名字段以“張”開頭的
QueryBuilder qb = QueryBuilders.prefixQuery("name","張");
//ids查詢:查詢指定ids的對應文檔
QueryBuilder qb = QueryBuilders.idsQuery().addIds("1","3");
//type查詢,查詢指定index下指定type的所有文檔
QueryBuilder qb = QueryBuilders.typeQuery("blog");
四.mapping
數據如何存放到索引對象上,需要有一個映射配置,包括:數據類型、是否存儲、是否分詞等
mapping是類似於數據庫中的表結構定義,主要作用如下:
定義index下的字段名
定義字段類型,比如數值型、浮點型、布爾型等
定義倒排索引相關的設置,比如是否索引、記錄position等
1)在插入文檔的時候,es會根據插入的數據自動生成mapping映射
2)自定義mapping
首先,創建一個空的index(blog2)
preBuiltTransportClient.admin().indices().prepareCreate("blog2").get();
此時mapping是空的{}
然後,新增mapping
// 1設置mapping
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.startObject("article")
.startObject("properties")
.startObject("id")
.field("type", "string")
.field("store", "yes")
.endObject()
.startObject("title")
.field("type", "string")
.field("store", "no")
.endObject()
.startObject("content")
.field("type", "string")
.field("store", "yes")
.endObject()
.endObject()
.endObject()
.endObject();
// 2 添加mapping
PutMappingRequest mapping = Requests.putMappingRequest("blog2").type("article").source(builder);
preBuiltTransportClient.admin().indices().putMapping(mapping).get();
刷新,重新查看索引信息如下:
發現:string會被自動轉換成text類型
【end】這個就是Java操作Elasticsearch的常用API啦,關於ik分詞器,下篇再見。