1、建SpringBoot项目:elaticsearch_springboot
2、改pom
注意如果你使用自动引入依赖,默认使用的springboot版本为最新的,需要将版本改低一点!!!
<?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 https://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.2.5.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>elaticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>elasticsearch</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.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-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--elasticsearch for springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3、配置类
两种方式:推荐第二种
方式一:spring-data(2~3.x版本配置)
spring:
data:
elasticsearch:
cluster-nodes: 192.168.77.138:9300
方式二: spring-data(新版本推荐配置)
/**
* @Author: xj0927
* @Description: RestHighLevelClient 客户端配置
* @Date Created in 2020-12-30 14:05
* @Modified By:
*/
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("192.168.77.138:9200") //===>与kibana客户端类型都是restful分格,都是连接9200端口
.build();
return RestClients.create(clientConfiguration).rest();
}
}
4、实体类
ES操作相关的实体类,可以只需要业务实体类的某一些字段
@Document: 代表一个文档记录
- indexName: 用来指定索引名称
- type: 用来指定索引类型
@Id: 用来将对象中id和ES中_id映射
@Field: 用来指定ES中的字段对应Mapping
- type: 用来指定ES中存储类型
- analyzer: 用来指定使用哪种分词器
/**
* [用在类上]作用: 将Emp的对象映射成ES中一条json格式文档
* indexName : 用来指定这个对象的转为json文档存入那个索引中 要求:ES服务器中之前不能存在此索引名
* type : 用来指定在当前这个索引下创建的类型名称
*/
@Document(indexName = "ems", type = "emp")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
@Id //与ES中_id进行映射
private String id;
/**
* @Description: 用在属性上 代表mapping中一个属性 一个字段
* type:属性 用来指定字段类型 analyzer:指定分词器
* @Author: xj0927
* @Date Created in 2020/12/30 14:38
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String name;
@Field(type = FieldType.Integer)
private Integer age;
@Field(type = FieldType.Date)
@JsonFormat(pattern = "yyyy-MM-dd")
private Date bir;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String content;
@Field(type = FieldType.Keyword)
private String address;
}
5、通用接口
对一些简单的crud操作,可以使用 ElasticSearchRespositoy 接口
/**
* @Author: xj0927
* @Description: ElasticsearchRepository :ES提供的操作CRUD接口
* 第一个参数:指定对象类型
* 第二个参数:ID类型
* @Date Created in 2020-12-30 14:23
* @Modified By:
*/
public interface EmpRepository extends ElasticsearchRepository<Emp,String> {
}
6、ElasticSearchRespositoy 实现基本crud
通过最定义接口继承ES提供的ElasticsearchRepository接口来实现
索引or更新一条记录
这种方式根据实体类中中配置自动在ES创建索引,类型以及映射
- 不传入id表示添加操作,会自动生成id
- 传入id,ES中有此id表示更新,没有表示添加
@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class TestSpringBootDataEs {
@Autowired
private BookRepository bookRespistory;
/**
* 添加索引和更新索引 id 存在更新 不存在添加
*/
@Test
public void testSaveOrUpdate(){
Book book = new Book();
book.setId("21");
book.setName("小陈");
book.setCreateDate(new Date());
book.setAuthor("李白");
book.setContent("这是中国的好人,这真的是一个很好的人,李白很狂");
bookRespistory.save(book);
}
}
删除一条记录
两种方式:根据id,根据对象属性值
@Test
public void testDelete(){
Book book = new Book();
book.setId("21");
bookRespistory.delete(book);
}
查询
/**
* 查询一个
*/
@Test
public void testFindOne(){
Optional<Book> byId = bookRespistory.findById("21");
System.out.println(byId.get());
}
/**
* 查询所有
*/
@Test
public void testFindAll(){
Iterable<Book> books = bookRespistory.findAll();
for (Book book : books) {
System.out.println(book);
}
}
查询并排序
@Test
public void testFindAllOrder(){
Iterable<Book> books = bookRespistory.findAll(Sort.by(Sort.Order.asc("createDate")));
books.forEach(book -> System.out.println(book) );
}
自定义基本查询
通过 ElasticsearchRepository 接口除了ES提供的api还可以在自定义接口中自定义一些查询的方法
Keyword | Sample | Elasticsearch Query String |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
举一些例子:
public interface BookRepository extends ElasticsearchRepository<Book,String> {
//根据作者查询
List<Book> findByAuthor(String keyword);
//根据内容查询
List<Book> findByContent(String keyword);
//根据内容和名字查
List<Book> findByNameAndContent(String name,String content);
//根据内容或名称查询
List<Book> findByNameOrContent(String name,String content);
//范围查询
List<Book> findByPriceBetween(Double start,Double end);
//查询名字以xx开始的
List<Book> findByNameStartingWith(String name);
//查询某个字段值是否为false
List<Book> findByNameFalse();
//.......
//根据名字查询,然后 根据Pageable 参数进行分页
//调用时:PageRequest page = PageRequest.of(0, 2);
List<Emp> findByContent(String name, Pageable pageable);
}
7、RestHighLevelClient 实现复杂查询
分页查询并排序
@Test
public void testSearchPage() throws IOException {
//查询请求
SearchRequest searchRequest = new SearchRequest();
//查询条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(0).size(2).sort("age", SortOrder.ASC).query(QueryBuilders.matchAllQuery());
//去哪个索引/类型查询
searchRequest.indices("ems").types("emp").source(sourceBuilder);
//====>查询方法
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = search.getHits().getHits();
for (SearchHit hit : hits) {
//字符串格式展示
System.out.println(hit.getSourceAsString());
}
}
高亮查询
@Test
public void testLight() throws IOException {
//集合存放查找到的数据
List<Emp> list = new ArrayList<>();
//查询请求
SearchRequest searchRequest = new SearchRequest();
//查询条件[对象]
SearchSourceBuilder builder = new SearchSourceBuilder();
//高亮配置
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("*").requireFieldMatch(false).preTags("<span style='color:red'>").postTags("</span>");
//具体按...查询
builder.from(0).size(2)
.sort("age", SortOrder.DESC)
.highlighter(highlightBuilder)
.query(QueryBuilders.multiMatchQuery("小黑喜欢小红", "name", "content"));
//从哪个索引/类型查找
searchRequest.indices("ems").types("emp").source(builder);
//===>查询方法
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
System.out.println("符合条件总数:" + searchResponse.getHits().getTotalHits());
System.out.println("最大得分:" + searchResponse.getHits().getMaxScore());
System.out.println("每条文档详细信息===>");
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit s :hits) {
//===>原文档部分
System.out.println(s.getSourceAsMap());
//返回对象
Emp emp = new Emp();
emp.setId((String) s.getSourceAsMap().get("id"));
emp.setName((String) s.getSourceAsMap().get("name"));
emp.setContent((String) s.getSourceAsMap().get("content"));
emp.setAddress((String) s.getSourceAsMap().get("address"));
emp.setAge((Integer) s.getSourceAsMap().get("age"));
//==>高亮部分
Map<String, HighlightField> highlightFields = s.getHighlightFields();
if(highlightFields.containsKey("name")){
emp.setName(highlightFields.get("name").fragments()[0].toString());
}
if(highlightFields.containsKey("content")){
emp.setContent(highlightFields.get("content").fragments()[0].toString());
}
list.add(emp);
}
//===>存入对象的文档[包括高亮部分]
System.out.println("===>存入对象的文档[包括高亮部分]");
list.forEach(emp -> {
System.out.println(emp);
});
}
为什么要分开拿原文档和高亮部分: