Java操作ElasticSearch
Java API
我的ElasticSearch集群的版本是6.2.4,導入elasticsearch相關的maven依賴也是6.2.4,不同版本的api可能會有差異
一:maven依賴
<!--elasticsearch核心依賴-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.2.4</version>
</dependency>
<!--elasticsearch客戶端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.2.4</version>
</dependency>
<!--日志-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<!--實體轉json-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.2</version>
</dependency>
<!--實體類簡化工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
2.單元測試的共有方法
TransportClient client;
@Before
//創建連接
public void connection() throws UnknownHostException {
//創建客戶端連接對象
//參數為config\elasticsearch.yml中對應的值 也就是集群名稱
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(InetAddress.getByName("192.168.118.3"), 9300));
client.addTransportAddress(new TransportAddress(InetAddress.getByName("192.168.118.4"), 9300));
client.addTransportAddress(new TransportAddress(InetAddress.getByName("192.168.118.5"), 9300));
}
@After
//釋放資源
public void close() {
client.close();
}
//遍歷結果集
public void iteratorSearchHit(SearchHits searchHits) {
System.out.println("符合查詢條件有:" + searchHits.getTotalHits() + "條");
//獲取迭代器
Iterator<SearchHit> iterator = searchHits.iterator();
System.out.println("開始進行遍歷------------------------------");
while (iterator.hasNext()) {
//獲取每個查詢對象
SearchHit searchHit = iterator.next();
//獲取字符串類型並進行打印
System.out.println(searchHit.getSourceAsString());
Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
System.out.println("符合搜索條件的標題是:=======" + sourceAsMap.get("title"));
/* for (Map.Entry<String,Object> map:sourceAsMap.entrySet()){
System.out.println("===================================");
System.out.println(map.getKey());
System.out.println(map.getValue());
}
*/
}
}
3.常規操作
@Test
//創建索引庫
public void createIndex() {
//索引名成必須小寫
client.admin().indices().prepareCreate("myindex1").get();
}
@Test
//添加映射
public void mapping() throws IOException, ExecutionException, InterruptedException {
XContentBuilder builder = XContentFactory.jsonBuilder().startObject()
.startObject("type1")
.startObject("properties")
.startObject("id")
.field("type", "integer")
.field("store", "true")
.endObject()
.startObject("title")
.field("type", "text")
.field("store", "true")
.field("analyzer", "ik_smart")
.endObject()
.startObject("content")
.field("type", "text")
.field("store", "true")
.field("analyzer", "ik_smart")
.endObject()
.endObject()
.endObject()
.endObject();
PutMappingRequest mappingRequest = Requests.putMappingRequest("myindex1")
.type("type1")
.source(builder);
client.admin().indices().putMapping(mappingRequest).get();
}
@Test
//給myindex1的type1創建文檔
public void createDocument() throws IOException {
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
xContentBuilder.startObject()
.field("id", 1)
.field("title", "ElasticSearch是一個基於Lucene的搜索服務器")
.field("content", "它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用 Java開發的,並作為Apache許可條款下的開放源碼發布,是當前流行的企業級搜索引擎。設計用於雲計算中,能夠達到 實時搜索,穩定,可靠,快速,安裝使用方便。")
.endObject();
//參數1:索引名 2:類型 3:id
client.prepareIndex("myindex1", "type1", "1").setSource(xContentBuilder).get();
}
@Test
//通過實體轉json創建文檔
public void jsonDocument() throws JsonProcessingException {
Type1 type1 = new Type1();
type1.setId(2);
type1.setTitle("通過實體轉json創建文檔");
type1.setContent("通過創建實體的方式,將實體轉json");
ObjectMapper objectMapper = new ObjectMapper();
client.prepareIndex("myindex1", "type1", type1.getId().toString())
.setSource(objectMapper.writeValueAsString(type1).getBytes(), XContentType.JSON)
.get();
}
@Test
//關鍵詞查詢
public void termQuery() {
//設置搜索條件,目標索引庫,目標類型,目標域
SearchResponse searchResponse = client.prepareSearch("myindex1")
.setTypes("type1")
.setQuery(QueryBuilders.termQuery("content", "實體")).get();
SearchHits hits = searchResponse.getHits();
iteratorSearchHit(hits);
}
@Test
//字符串查詢
public void stringQuery() {
//設置搜索條件,目標索引庫,目標類型
SearchResponse searchResponse = client.prepareSearch("myindex1")
.setTypes("type1")
.setQuery(QueryBuilders.queryStringQuery("搜索實體")).get();
SearchHits hits = searchResponse.getHits();
iteratorSearchHit(hits);
}
@Test
//根據文檔ID進行查詢
public void idQuery() {
SearchResponse searchResponse = client.prepareSearch("myindex1")
.setQuery(QueryBuilders.idsQuery("type1").addIds("2"))
.get();
iteratorSearchHit(searchResponse.getHits());
}
//分頁之前的操作,批量添加文檔
@Test
public void batchInsert() throws JsonProcessingException {
Type1 type1;
for (int i = 1; i <= 50; i++) {
type1 = new Type1();
type1.setId(i);
type1.setTitle(i + "通過實體轉json創建文檔");
type1.setContent(i + "通過創建實體的方式,將實體轉json");
ObjectMapper objectMapper = new ObjectMapper();
client.prepareIndex("myindex1", "type1", type1.getId().toString())
.setSource(objectMapper.writeValueAsString(type1).getBytes(), XContentType.JSON)
.get();
}
}
//搜索文檔並分頁顯示
@Test
public void pageDocument() {
SearchResponse searchResponse = client.prepareSearch("myindex1")
.setTypes("type1")
.setQuery(QueryBuilders.matchAllQuery())
//setFrom():從第幾條開始檢索,默認是0。
// setSize():每頁最多顯示的記錄數默認是十
.setFrom(0)
.setSize(5)
.get();
iteratorSearchHit(searchResponse.getHits());
}
//模擬搜索結果高亮顯示
@Test
public void highlight() {
//設置查詢條件
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("myindex1")
.setTypes("type1")
.setQuery(QueryBuilders.termQuery("title", "實體"));
//高亮設置
HighlightBuilder highlightBuilder = new HighlightBuilder();
//開頭的標簽信息
highlightBuilder.preTags("<font style='color:red'>");
//結尾的標簽
highlightBuilder.postTags("</font>");
highlightBuilder.field("title");
searchRequestBuilder.highlighter(highlightBuilder);
SearchResponse searchResponse = searchRequestBuilder.get();
Iterator<SearchHit> iterator = searchResponse.getHits().iterator();
while (iterator.hasNext()) {
SearchHit hit = iterator.next();
System.out.print("正常String方式打印文檔搜索內容====");
System.out.println(hit.getSourceAsString());
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
//遍歷集合,輸出高亮數據
//方式1
Text[] titles = highlightFields.get("title").getFragments();
for (Text str : titles) {
System.out.println(str);
}
}
}
Spring Data ElasticSearch
Spring Data是一個用於簡化數據庫訪問,並支持雲服務的開源框架。其主要目標是使得對數據的訪問變得方便快捷,並支持map-reduce框架和雲計算數據服務。 Spring Data可以極大的簡化JPA的寫法,可以在幾乎不用寫實現的情況下,實現對數據的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。
筆者的ElasticSearch集群的版本是6.2.4,導入spring-data-elasticsearch的maven依賴也是3.1.5.RELEASE,不同版本的api可能會有差異
一:准備maven依賴
<!--elasticsearch核心依賴-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.2.4</version>
</dependency>
<!--elasticsearch客戶端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.2.4</version>
</dependency>
<!--日志-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<!--實體類簡化工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
<!--springframework-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!--spring-data-elasticsearch-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.1.5.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport‐netty4‐client</artifactId>
</exclusion>
</exclusions>
</dependency>
二:創建實體
package com.yjc.entity;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
//lombok相當於get,set,toSting等一系列方法
@Data
//代表文檔對象(索引庫,類型)
@Document(indexName = "myindex2",type = "article")
public class Article {
//文檔主鍵,唯一
@Id
//store是否存儲(默認false),index是否分詞(默認true),type類型
@Field(store = true,index = false,type = FieldType.Integer)
private Integer id;
//下面配置代表 進行存儲並以ik_smart方式分詞,(默認開啟分詞)保持的類型為text,進行查詢的時候按照ik_smart方式進行分詞
@Field(store = true,analyzer ="ik_smart",searchAnalyzer = "ik_smart",type = FieldType.Text)
private String title;
//下面配置代表 進行存儲並以ik_smart方式分詞,保持的類型為text,進行查詢的時候按照ik_smart方式進行分詞
@Field(store = true,analyzer ="ik_smart",searchAnalyzer = "ik_smart",type = FieldType.Text)
private String content;
}
三:創建DAO和Service
ArticleDao
package com.yjc.dao;
import com.yjc.entity.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
/**
* ElasticsearchRepository<要操作的實體類,ID在實體類中類型>
* */
public interface ArticleDao extends ElasticsearchRepository<Article,Integer> {
//根據標題查詢
List<Article> findByTitle(String condition);
//根據標題查詢(含分頁)
Page<Article> findByTitle(String condition, Pageable pageable);
//根據id
List<Article> findById(String condition);
}
ArticleService
package com.yjc.service;
import com.yjc.entity.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface ArticleService {
//添加
void save(Article article);
//刪除
void delete(Article article);
//查詢全部
Iterable<Article> findAll();
//分頁查詢
Page<Article> findAll(Pageable pageable);
//根據標題查詢
List<Article> findByTitle(String condition);
//根據標題查詢(含分頁)
Page<Article> findByTitle(String condition, Pageable pageable);
//根據內容搜索並分頁
List<Article> findById(String condition);
}
ArticleServiceImpl
package com.yjc.service.impl;
import com.yjc.dao.ArticleDao;
import com.yjc.entity.Article;
import com.yjc.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
ArticleDao articleDao;
@Override
public void save(Article article) {
articleDao.save(article);
}
@Override
public void delete(Article article) {
articleDao.delete(article);
}
@Override
public Iterable<Article> findAll() {
return articleDao.findAll();
}
@Override
public Page<Article> findAll(Pageable pageable) {
return articleDao.findAll(pageable);
}
@Override
public List<Article> findByTitle(String condition) {
return articleDao.findByTitle(condition);
}
@Override
public Page<Article> findByTitle(String condition, Pageable pageable) {
return articleDao.findByTitle(condition,pageable);
}
@Override
public List<Article> findById(String condition) {
return articleDao.findById(condition);
}
}
四:創建Spring的核心配置文件
applicationContext.xml,注意更換命名空間
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd "> <!--創建包掃描器,掃描Dao,自動創建實例--> <elasticsearch:repositories base-package="com.yjc.dao"/> <!--掃描Service--> <context:component-scan base-package="com.yjc.service"/> <!--配置es的連接--> <elasticsearch:transport-client id="client" cluster-nodes="192.168.118.3:9300" cluster-name="elasticsearch"/> <!--es模板對象--> <bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate"> <constructor-arg name="client" ref="client"/> </bean> </beans>
五:測試
package com.yjc.test;
import com.yjc.entity.Article;
import com.yjc.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
//啟動單元測試的時候加載的配置文件
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpringDataESTest {
@Autowired
ArticleService articleService;
//注入連接對象
@Autowired
TransportClient client;
//注入模板對象
@Autowired
ElasticsearchTemplate elasticsearchTemplate;
@Test
//創建索引
public void createIndex() {
//配置在實體類中已經配置好了,直接創建並添加映射
elasticsearchTemplate.createIndex(Article.class);
elasticsearchTemplate.putMapping(Article.class);
}
@Test
//保存文檔
public void saveArticle() {
Article article = new Article();
article.setId(101);
article.setTitle("測試SpringData ElasticSearch");
article.setContent("Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操 作,將原始操作elasticSearch的客戶端API 進行封裝 \n" + " Spring Data為Elasticsearch Elasticsearch項目提供集成搜索引擎");
articleService.save(article);
}
@Test
//修改文檔
public void update() {
Article article = new Article();
article.setId(100);
article.setTitle("修改SpringData ElasticSearch");
article.setContent("修改Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操 作,將原始操作elasticSearch的客戶端API 進行封裝 \n" + " Spring Data為Elasticsearch Elasticsearch項目提供集成搜索引擎");
articleService.save(article);
}
@Test
//刪除文檔
public void delete(){
Article article = new Article();
article.setId(100);
articleService.delete(article);
}
@Test
//分頁查詢
public void findAllPage(){
Pageable pageable=PageRequest.of(0,10);
Page<Article> all = articleService.findAll(pageable);
for (Article article:all.getContent()){
System.out.println(article);
}
}
@Test
//帶條件查詢
public void findByTitle(){
List<Article> articles = articleService.findByTitle("測試");
for (Article article:articles){
System.out.println(article);
}
}
@Test
//待條件查詢加分頁
public void findByTitlePage(){
Pageable pageable=PageRequest.of(0,1);
Page<Article> articles = articleService.findByTitle("引擎", pageable);
for (Article article:articles.getContent()){
System.out.println(article);
}
}
@Test
//根據id進行查詢
public void findByContent(){
List<Article> articles = articleService.findById("100");
for (Article article:articles){
System.out.println(article);
}
}
}

