org.springframework.boot
spring-boot-starter-data-elasticsearch
spring.data.elasticsearch.cluster-nodes=10.111.27.202:9300
@Document(indexName = "resource", type = "resources")
public class Resource {
private Long id;
@Field(type = FieldType.text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String name;
private String type;
private Date createTime;
private Date updateTime;
private String url;
private Integer readNumber;
private Integer likeNumber;
@Field(type = FieldType.text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String content;
@Field(type = FieldType.text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String writer;
private String resource;
private Date publishTime;
}
我们主要看@Document和@Field两个注解
这两个注解在springdata elasticsearch包下,springdata是spring的一项project,主要是封装了一个关系型数据库和非关系型数据库,比如MongoDB redis MySQL等,方便我们来使用。
package org.springframework.data.elasticsearch.annotations;
Document
Document对应的就是elasticsearch中的document
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Document {
String indexName();
String type() default "";
boolean useServerConfiguration() default false;
short shards() default 5;
short replicas() default 1;
String refreshInterval() default "1s";
String indexStoreType() default "fs";
boolean createIndex() default true;
}
indexNmae 对应的是elasticsearch中的index,我们看到createIndex默认值是true,所以当elastic search中没有对应的index的时候会自己创建
document可以分组,比如weacher这个index中,可以按照城市分组,比如 北京 上海
注意事项: 不建议使用type 因为按照elastic search的计划后面的版本7.0以后会移除type
Field
我们就可以。理解为每个document字段,这个和jpa的column有点类似
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Inherited
public @interface Field {
FieldType type() default FieldType.Auto;
boolean index() default true;
DateFormat format() default DateFormat.none;
String pattern() default "";
boolean store() default false;
boolean fielddata() default false;
String searchAnalyzer() default "";
String analyzer() default "";
String[] ignoreFields() default {};
boolean includeInParent() default false;
}
需要了解的几个地方
返回值是FieldType 类型
public enum FieldType {
text, Integer, Long, Date, Float, Double, Boolean, Object, Auto, Nested, Ip, Attachment, keyword
}
可以理解为数据类型
analyzer 指定分词器
searchAnalyzer 查询时候使用的分词器
上面的代码自动会去判断是否存在index,不存在创建
通过上面的代码创建的index如下:
{
"resource": {
"aliases": {},
"mappings": {
"resources": {
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"createTime": {
"type": "long"
},
"id": {
"type": "long"
},
"name": {
"type": "text",
"analyzer": "ik_max_word"
},
"publishTime": {
"type": "long"
},
"url": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"writer": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
},
"settings": {
"index": {
"refresh_interval": "1s",
"number_of_shards": "5",
"provided_name": "resource",
"creation_date": "1524469358634",
"store": {
"type": "fs"
},
"number_of_replicas": "1",
"uuid": "Q43LJHzkRJW5_kJtpumI-g",
"version": {
"created": "6010299"
}
}
}
}
}
ElasticsearchRepository
熟悉spring data 这个project的朋友,应该会比较熟悉,简单说就是spring data 项目帮忙做了一些封装,只要继承相关的repository就可以做一些增删改查的操作了
首先我们继承ElasticsearchRepository这个接口,绑定相关的实体类和id类型
public interface ResourceRepository extends ElasticsearchRepository{
}
数据插入
@Test
public void contextLoads() {
long count = resourceService.resourcesCount();
System.out.println("总数:" + count);
long start = System.currentTimeMillis();
//查询数据,插入到elastic search
int pages = (int) (count / 200);
int page = 1;
while (page < pages) {
PageInfo resources = resourceService.resources(1, 200);
page++;
List list = resources.getList();
resourceRepository.saveAll(list);
}
long end = System.currentTimeMillis();
System.out.println("执行结束:" + (end - start));
}
上面的代码是将数据库中查询到的数据插入到elastic search 中
数据查询
@Test
public void search() {
long start = System.currentTimeMillis();
resourceRepository.findById(200L);
long end = System.currentTimeMillis();
System.out.println("elastic 查询时间:" + (end - start));
start = System.currentTimeMillis();
resourceService.findResourceById(200L);
end = System.currentTimeMillis();
System.out.println("mysql 查询时间:" + (end - start));
}
上面的代码是两种实现,一种从数据库中查询,一种从elastic search中查询
elastic 查询时间:123
mysql 查询时间:297
我MySQL数据库中只有三千多条数据,从执行结果来看,elastic search的查询效率更高,可以考虑用来作为缓存使用
数据全文检索
@Test
public void searchContent(){
Iterable search = resourceRepository.search(new MatchQueryBuilder("content", "心怡"));
search.forEach(resource -> {
System.out.println(resource.getName());
System.out.println(resource.getContent());
});
}
全文检索含有'心怡'关键字