概念
索引(Index):索引库,一个Elasticsearch可以有多个索引库 (相当于 mysql 创建的数据库)
类型(Type):分组,一个索引库可以有多个分组 (相当于 mysql 的数据表)
文档(Document):相当于mysql数据表中的每一行数据
字段(Fields):相当于 mysql 字段名称
mapping:相当于 mysql 的表结构
下载并安装 Elasticsearch
参考 https://blog.csdn.net/yjclsx/article/details/81302041
基本用法
Elasticsearch调用都是遵循restful风格方式进行调用。
详细参考https://www.cnblogs.com/swordfall/p/8923087.html
集成springboot
pom文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>elasticsearch</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC1</spring-cloud.version>
<sharding.jdbc.version>3.0.0</sharding.jdbc.version>
<druid.version>1.1.6</druid.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.2.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring_boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>
配置连接Elasticsearch
package com.elasticsearch.constants;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
@Configuration
public class ElasticsearchContants {
@Bean
public TransportClient initElasticsearch() {
TransportClient transportClient = null;
try {
// 配置信息
Settings esSetting = Settings.builder()
.put("cluster.name", "elasticsearch") //集群名字
.put("thread_pool.search.size", Integer.parseInt("5"))//增加线程池个数,暂时设为5
.build();
//配置信息Settings自定义
transportClient = new PreBuiltTransportClient(esSetting);
TransportAddress transportAddress = new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300);
transportClient.addTransportAddresses(transportAddress);
} catch (Exception e) {
}
return transportClient;
}
}
工具类
package com.elasticsearch.utils;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.elasticsearch.constants.ElasticsearchContants;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class ElasticsearchUtils {
@Autowired
private ElasticsearchContants elasticsearchContants;
private static TransportClient client;
@PostConstruct
private void init(){
client = elasticsearchContants.initElasticsearch();
}
/**
* 创建索引库
*
* @param index
* @return
*/
public static boolean createIndex(String index) {
if(isIndexExist(index)){
return true;
}
CreateIndexResponse createIndexResponse = client.admin().indices().prepareCreate(index).execute().actionGet();
return createIndexResponse.isAcknowledged();
}
/**
* 创建复杂索引,包括初始化类型,mapping
* @param index
* @param type
* @param mapping 类似json数据字符串
* @return
*/
public static boolean createIndex(String index, String type, XContentBuilder mapping){
if(isIndexExist(index)){
return true;
}
//umber_of_replicas 是数据备份数,如果只有一台机器,设置为0
//number_of_shards 是数据分片数,默认为5,有时候设置为3
Settings settings = Settings.builder().put("index.number_of_shards", 3)
.put("index.number_of_replicas", 0).build();
PutMappingResponse putMappingResponse = client.admin().indices()
.preparePutMapping(index)
.setType(type)// setting
.setSource(mapping)// type,mapping
.get();
return putMappingResponse.isAcknowledged();
}
/**
* 删除索引库
* @param index
* @return
*/
public static boolean delIndex(String index) {
if(!isIndexExist(index)){
return true;
}
AcknowledgedResponse acknowledgedResponse = client.admin().indices().prepareDelete(index).execute().actionGet();
return acknowledgedResponse.isAcknowledged();
}
/**
* 索引库是否存在
* @param index
* @return
*/
public static boolean isIndexExist(String index){
IndicesExistsResponse indicesExistsResponse = client.admin().indices().exists(new IndicesExistsRequest(index)).actionGet();
return indicesExistsResponse.isExists();
}
/**
* 数据添加,id自定义
* @param jsonObject
* @param index
* @param type
* @param id
* @return
*/
public static String addData(JSONObject jsonObject, String index, String type, String id){
IndexResponse indexResponse = client.prepareIndex(index, type, id).setSource(jsonObject).get();
return indexResponse.getId();
}
/**
* 数据添加,id默认
* @param jsonObject
* @param index
* @param type
* @return
*/
public static String addData(JSONObject jsonObject, String index, String type){
IndexResponse indexResponse = client.prepareIndex(index, type).setSource(jsonObject).get();
return indexResponse.getId();
}
/**
* 通过 index,type,id 删除数据
* @param index
* @param type
* @param id
*/
public static void delDataById(String index, String type,String id){
client.prepareDelete(index, type, id).execute().actionGet();
}
/**
* 通过 index,type,id 修改数据
* @param index
* @param type
* @param id
*/
public static void updateDataById(JSONObject jsonObject,String index, String type,String id){
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.index(index).type(type).id(id).doc(jsonObject);
ActionFuture<UpdateResponse> update = client.update(updateRequest);
}
/**
* 通过 index,type,id 查询数据
* @param index
* @param type
* @param id 需要显示的字段,逗号分隔(不传则展示全部字段)
*/
public static Map<String, Object> queryDataById(String index, String type, String id, String fields){
GetRequestBuilder getRequestBuilder = client.prepareGet(index, type, id);
if(!StringUtils.isEmpty(fields)){
getRequestBuilder.setFetchSource(fields.split(","),null);
}
GetResponse documentFields = getRequestBuilder.execute().actionGet();
return documentFields.getSource();
}
/**
*
* @param index
* @param type 类型名称,可传入多个type逗号分隔
* @param query 查询条件
* @param size 需要查询出多少条结果
* @param fields 需要显示的字段,逗号分隔(不传则展示全部字段)
* @param sortField 排序字段
* @param sortType 排序方式 asc desc
* @return
*/
public static List<Map<String, Object>> searchDataList(String index, String type, QueryBuilder query, Integer size, String fields, String sortField, SortOrder sortType){
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index);
//设置查询的 type
if (!StringUtils.isEmpty(type)) {
searchRequestBuilder.setTypes(type.split(","));
}
//设置查询条件
searchRequestBuilder.setQuery(query);
if (!StringUtils.isEmpty(fields)) {
searchRequestBuilder.setFetchSource(fields.split(","),null);
}
searchRequestBuilder.setFetchSource(true);
//设置排序
if (!StringUtils.isEmpty(sortField)) {
searchRequestBuilder.addSort(sortField, sortType);
}
//文档大小限制
if(size != null && size > 0){
searchRequestBuilder.setSize(size);
}
SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
//共查询的数据数量
long totalSize = searchResponse.getHits().totalHits;
//处理的数据数量
long dealSize = searchResponse.getHits().totalHits;
System.out.println("共查询到[" + totalSize + "]条数据,处理数据条数[" + dealSize + "]");
if (searchResponse.status().getStatus() == 200) {
return setSearchResponse(searchResponse);
}
return null;
}
/**
* 将查询结果返回为list<Map>
* @param searchResponse
* @return
*/
private static List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse){
List<Map<String, Object>> sourceList = new ArrayList<Map<String, Object>>();
StringBuffer stringBuffer = new StringBuffer();
for (SearchHit searchHit : searchResponse.getHits().getHits()) {
searchHit.getSourceAsMap().put("id", searchHit.getId());
sourceList.add(searchHit.getSourceAsMap());
}
return sourceList;
}
}
编写测试类
import com.alibaba.fastjson.JSONObject;
import com.elasticsearch.ElasticsearchApplication;
import com.elasticsearch.constants.ElasticsearchContants;
import com.elasticsearch.utils.ElasticsearchUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = ElasticsearchApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class TestJava {
@Autowired
ElasticsearchContants elasticsearchContants;
@Test
public void elasticsearchTest(){
//新增 test 索引库
ElasticsearchUtils.createIndex("test");
//新增分组 user,并添加数据,id自己生成
JSONObject jsonObject = new JSONObject();
jsonObject.put("name","李四1");
jsonObject.put("city","北京1");
jsonObject.put("age","111");
jsonObject.put("desc","这是李四的描述1");
ElasticsearchUtils.addData(jsonObject,"test","user","1");
//新增分组 user,并添加数据,id默认生成
jsonObject = new JSONObject();
jsonObject.put("name","王五");
jsonObject.put("city","上海");
jsonObject.put("age","21");
jsonObject.put("desc","王五就是我,我就是隔壁老王");
ElasticsearchUtils.addData(jsonObject,"test","user");
//根据id删除
// ElasticsearchUtils.delDataById("test","user","1");
//修改id为1的用户信息
JSONObject jsonObject = new JSONObject();
jsonObject.put("name","李四");
jsonObject.put("city","北京");
jsonObject.put("age","11");
jsonObject.put("desc","这是李四的描述");
ElasticsearchUtils.updateDataById(jsonObject,"test","user","1");
//查询id为1 的用户姓名
System.out.println(JSONObject.toJSON(ElasticsearchUtils.queryDataById("test","user","1","name")).toString());
//打印结果 [{"name":"王五","id":"8vIqC3QBsN7wCGyBOPw6","city":"上海","age":"21","desc":"王五就是我,我就是隔壁老王"}]
QueryBuilder queryBuilder = QueryBuilders.commonTermsQuery("name","王");
System.out.println(JSONObject.toJSON(ElasticsearchUtils.searchDataList("test","user",queryBuilder,null,null,null, null)));
//打印结果 [{"name":"王五","id":"8vIqC3QBsN7wCGyBOPw6","city":"上海","age":"21","desc":"王五就是我,我就是隔壁老王"}]
QueryBuilder queryBuilder1 = QueryBuilders.commonTermsQuery("name","王五");
System.out.println(JSONObject.toJSON(ElasticsearchUtils.searchDataList("test","user",queryBuilder1,null,null,null, null)));
//打印结果 [{"name":"王五","city":"上海","id":"8vIqC3QBsN7wCGyBOPw6"},{"name":"李四","city":"北京","id":"1"}]
QueryBuilder queryBuilder2 = QueryBuilders.commonTermsQuery("desc","就是");
System.out.println(JSONObject.toJSON(ElasticsearchUtils.searchDataList("test","user",queryBuilder2,100,"name,city",null, null)));
}
}
注意
测试类中查询时用到的 QueryBuilders.commonTermsQuery 只是其中一种查询方式,其他用法参考 https://www.cnblogs.com/xiang–liu/p/11498367.html
可能出现的错误
如上图所示错误,出现原因为连接Elasticsearch错误。没启动,集群名称或者端口号写错了等。要按照配置文件来写。
但是要注意我配置的端口号为9200,但是连接9200 会报错,需要写成9300。9200作为Http协议,主要用于外部通讯。9300作为集群通讯。上面的配置方式是集群方式,虽然只有一个节点,但是也要用9300端口。
我用上面代码,给name字段排序,然后出现错误。原因 Elasticsearch 默认只支持数字和日期排序;
如果要实现,给索引设置mapping,将排序字段配置成 fielddata:true也可以支持。
ElasticsearchUtils.createIndex("test_1","user_1",getMappering())
private XContentBuilder getMappering(){
XContentBuilder builder = null;
try {
//{"user_1" : {"properties" : {"age" : { "type" : "long"},"city" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}},"fielddata":true},"name" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}},"desc" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}}}}}
builder= XContentFactory.jsonBuilder()
.startObject().startObject("user_1").startObject("properties").
startObject("age").field("type","long").endObject().
startObject("city").field("type","text").field("fielddata","true").endObject().
startObject("name").field("type","text").endObject()
.endObject().endObject().endObject();
} catch (IOException e) {
e.printStackTrace();
}
return builder;
}
调用此方法可设置mapping