前些天看完了一本关于elasticsearch的书籍,并且做了一个elasticsearch相关项目,对与es也算是有了一定程度的了解,不过看书向来都是一边看一边忘的,以此文章记录一些es的简单用法。
由于本人用的es版本为es 7.2的镜像,故所有依赖都是es 7.2 版本。以下为依赖代码。
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.2.0</version>
</dependency>
<!--这个依赖 7.x 版本可以不添加,但是由于本人代码用到,所以不去除-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>7.2.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.2.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.2.0</version>
</dependency>
下面为ElasticsearchConfig的配置代码
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
/**
* @Author lidai
* @Date 2020/1/7 16:20
*/
@Configuration
public class ElasticsearchConfig {
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private int port;
@Value("${elasticsearch.scheme}")
private String scheme;
@Value("${elasticsearch.timeout}")
private int timeout;
@Bean(name = "highLevelClient")
public RestHighLevelClient restHighLevelClient() {
//可以传httpHost数组
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port, scheme));
builder.setRequestConfigCallback(requestConfigBuilder -> {
//设置超时
return requestConfigBuilder.setSocketTimeout(timeout);
});
return new RestHighLevelClient(builder);
}
/**
* es7 已废弃 TransportClient,但是代码记录中用到,故留存。7.x版本可以直接舍弃
*
* @return
*/
@Bean
public TransportClient transportClient() {
try {
Settings settings = Settings.builder().put("cluster.name", "elasticsearch")
.put("client.transport.sniff", true)
.build();
TransportClient transportClient = new PreBuiltTransportClient(settings);
TransportAddress address = new TransportAddress(InetAddress.getByName(host), port);
transportClient.addTransportAddress(address);
return transportClient;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
es 6.x中好像在存储或修改时不能直接使用json字符串了(我记得是这样,如果能用就更好了),所以需要使用XContentBuilder来对字段进行处理,以下是一个处理的工具类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Map;
/**
* @Author lidai
* @Date 2020/1/7 18:14
*/
public class ElasticsearchUtils {
/**
* 将实体转化为 XContentBuilder 以便存储es
*
* @param xContentBuilder
* @param object
* @return
*/
public static XContentBuilder objectToXContentBuilder(XContentBuilder xContentBuilder, Object object) {
try {
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(object));
xContentBuilder.startObject();
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
xContentBuilder.field(entry.getKey(), entry.getValue());
}
xContentBuilder.endObject();
} catch (IOException e) {
e.printStackTrace();
}
return xContentBuilder;
}
}
以下为增删改查的Java示例代码 ,目前代码都是es6.x版本,7.x版本有时间在加上去。值得注意的是es7.x中 TransportClient类已经过期。所以以下示例代码中凡是使用TransportClient的示例代码均为 elasticsearch 6.x 版本。
import com.alibaba.fastjson.JSONObject;
import com.demo.interview.es.domain.ElasticsearchPage;
import com.demo.interview.es.domain.Person;
import com.demo.interview.es.utils.ElasticsearchUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @Author lidai
* @Date 2020/1/7 18:12
*/
@Slf4j
@RestController
@RequestMapping("/elasticsearch")
public class ElasticsearchController {
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
static DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
static Person person = new Person(1L, "test", 20, 0, LocalDate.parse("2020-01-01").format(formatter), "备注", LocalDateTime.now().format(formatter2));
final String DEMO_INDEX = "demo_index";
final String DEMO_TYPE = "demo_type";
@Autowired
@Qualifier(value = "highLevelClient")
private RestHighLevelClient highLevelClient;
@Autowired
private TransportClient transportClient;
/**
* 新增
*
* @param person
* @throws Exception
*/
public void createIndex(Person person) throws Exception {
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
xContentBuilder = ElasticsearchUtils.objectToXContentBuilder(xContentBuilder, person);
//创建索引
IndexResponse indexResponse = transportClient.prepareIndex(DEMO_INDEX, DEMO_TYPE, person.getId().toString())
.setSource(xContentBuilder)
//立即生效,无此需求可以不设置
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.execute().actionGet();
}
/**
* 修改
*
* @param object
* @throws IOException
*/
public void updateIndex(Person person) throws IOException {
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
xContentBuilder = ElasticsearchUtils.objectToXContentBuilder(xContentBuilder, person);
UpdateResponse updateResponse = transportClient.prepareUpdate(DEMO_INDEX, DEMO_TYPE, person.getId().toString())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.setDoc(xContentBuilder).get();
}
/**
* 批量修改
*
* @param ids
* @throws IOException
*/
public void batchUpdate(String[] ids) throws IOException {
BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();
for (String id : ids) {
bulkRequestBuilder.add(transportClient.prepareUpdate(DEMO_INDEX, DEMO_TYPE, id)
.setDoc(XContentFactory.jsonBuilder().startObject().field("deleted", 1).endObject()));
}
BulkResponse response = bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
if (response.hasFailures()) {
throw new ElasticsearchException(response.buildFailureMessage());
}
}
/**
* 批量新增
*
* @param persons
* @throws IOException
*/
public void batchInsert(List<Person> persons) throws IOException {
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();
//添加es
for (Person person : persons) {
//注意批量操作时数据为null会报异常
bulkRequestBuilder.add(transportClient.prepareIndex(DEMO_INDEX, DEMO_TYPE, person.getId().toString())
.setSource(ElasticsearchUtils.objectToXContentBuilder(xContentBuilder, person)));
}
BulkResponse responses = bulkRequestBuilder.get();
if (responses.hasFailures()) {
throw new ElasticsearchException(responses.buildFailureMessage());
}
}
/**
* 搜索示例
*
* @param params
* @return
*/
public ElasticsearchPage<Person> searchDemo(Map<String, Object> params) {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(QueryBuilders.termQuery("deleted", 0));
String keyword = (String) params.get("keyword");
Integer news = (Integer) params.get("news");
Integer status = (Integer) params.get("status");
Integer columnCategory = (Integer) params.get("columnCategory");
String year = (String) params.get("year");
Integer pageSize = (Integer) params.get("pageSize");
Integer pageNum = (Integer) params.get("pageNum");
String[] messageColumn = {"messageTitle", "messageSource", "content", "tags", "issuer"};
//keyword字段类别搜索
if (news != null && StringUtils.hasText(keyword)) {
switch (news) {
case 1:
boolQueryBuilder.must(QueryBuilders.multiMatchQuery(keyword, messageColumn));
break;
case 2:
boolQueryBuilder.must(QueryBuilders.matchQuery("messageTitle", keyword));
break;
case 3:
boolQueryBuilder.must(QueryBuilders.matchQuery("content", keyword));
break;
case 4:
boolQueryBuilder.must(QueryBuilders.matchQuery("messageSource", keyword));
break;
case 5:
boolQueryBuilder.must(QueryBuilders.matchQuery("tags", keyword));
break;
case 6:
boolQueryBuilder.must(QueryBuilders.matchQuery("issuer", keyword));
break;
default:
break;
}
}
//发布状态搜索
if (status != null) {
switch (status) {
case 1:
boolQueryBuilder.must(QueryBuilders.matchAllQuery());
break;
case 2:
boolQueryBuilder.must(QueryBuilders.termQuery("status", 2));
break;
case 3:
boolQueryBuilder.must(QueryBuilders.termQuery("status", 3));
break;
default:
break;
}
}
//栏目类别搜索
if (columnCategory != null) {
switch (columnCategory) {
case 1:
boolQueryBuilder.must(QueryBuilders.matchAllQuery());
break;
case 2:
boolQueryBuilder.must(QueryBuilders.termQuery("columnCategory", 2));
break;
case 3:
boolQueryBuilder.must(QueryBuilders.termQuery("columnCategory", 3));
break;
default:
break;
}
}
//年份搜索,多年分传参形式为{"2016","2017","2018","2019","2020"}
if (StringUtils.hasText(year)) {
try {
Integer y = Integer.valueOf(year);
boolQueryBuilder.must(QueryBuilders.rangeQuery("updateDate").from(year + "-1-1").to(year + "-12-31"));
} catch (NumberFormatException e) {
String[] yearList = year.split(",");
int max = Arrays.stream(yearList).mapToInt(Integer::valueOf).max().getAsInt();
int min = Arrays.stream(yearList).mapToInt(Integer::valueOf).min().getAsInt();
boolQueryBuilder.must(QueryBuilders.rangeQuery("updateDate").from(min + "-1-1").to(max + "-12-31"));
}
}
SearchResponse searchResponse = transportClient.prepareSearch(DEMO_INDEX)
.setTypes(DEMO_TYPE)
.setQuery(boolQueryBuilder)
.setFrom((pageNum - 1) * pageSize)
.setSize(pageSize)
.addSort("status", SortOrder.DESC)
.addSort("updateDate", SortOrder.DESC)
.addSort("id", SortOrder.DESC)
.setExplain(true)
.execute()
.actionGet();
SearchHits hits = searchResponse.getHits();
int totalHits = (int) hits.getTotalHits().value;
SearchHit[] searchHits = hits.getHits();
List<Person> persons = new ArrayList<>(10);
for (SearchHit searchHit : searchHits) {
String sourceAsString = searchHit.getSourceAsString();
Person person = JSONObject.parseObject(sourceAsString, Person.class);
persons.add(person);
}
return ElasticsearchPage.<Person>of(pageNum, pageSize, totalHits, persons);
}
/**
* 查询分词结果,str为要分析的字符串,使用|将分词结果隔开
*
* @param str
* @return
*/
public String queryAnalyzer(String str) {
if (StringUtils.hasText(str)) {
AnalyzeRequest analyzeRequest = new AnalyzeRequest(DEMO_INDEX).text(str)
.analyzer("ik_max_word");
List<AnalyzeResponse.AnalyzeToken> tokens = this.transportClient.admin().indices().analyze(analyzeRequest)
.actionGet().getTokens();
StringBuilder sb = new StringBuilder();
for (AnalyzeResponse.AnalyzeToken token : tokens) {
sb.append(token.getTerm());
sb.append("|");
}
str = sb.toString().substring(0, sb.toString().length() - 1);
}
return str;
}
}
以上代码为求方便并未测试(后续有时间会测试),有问题欢迎指出,谢谢。
另外代码中 7.x版本代码暂无,有时间再添加。