引入项目依赖,下面只引入关键依赖。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
不同的版本有不同的依赖,请选择自己需要的版本,下图是具体的信息。
Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Boot |
---|---|---|---|
- | |||
2020.0.0[1] | 4.1.x[1] | 7.9.3 | 2.4.x[1] |
- | - | - | - |
Neumann | 4.0.x | 7.6.2 | 2.3.x |
Moore | 3.2.x | 6.8.12 | 2.2.x |
Lovelace | 3.1.x | 6.2.2 | 2.1.x |
Kay[2] | 3.0.x[2] | 5.5.0 | 2.0.x[2] |
Ingalls[2] | 2.1.x[2] | 2.4.0 | 1.5.x[2] |
对应文档:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/
在当前的 SpringBoot 2.4 +
版本,已经不再使用 TransportClient
和 ElasticsearchTemplate
,而是推荐使用:ElasticsearchRestTemplate
,同时此时不需要手动引入关键类,只需要在 application.peroperties
中配置如下信息即可。
spring.elasticsearch.rest.uris=http://localhost:9200
使用的时候,通过 Autowired
注入<span>ElasticsearchRestTemplate</span>
即可。
假如有一个实体类,我们定义如下:
@Setting(settingPath = "es/es-setting.json")
@Document(indexName = "book")
public class Book {
@Id
private String id;
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ue-ngram")
private String author;
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
private String name;
@Field(type = FieldType.Date, format = DateFormat.date)
private LocalDate publishDate;
@Field(type = FieldType.Date, format = DateFormat.date_time)
private LocalDateTime publishDateTime;
//get set toString 省略
}
@Setting
表示的是ES的配置信息,包括自定义的索引器、分片等信息。不知道如何定义的可以参考文章:自定义分词器案例@Documen
中 indexName 是索引的名称@Filed
中的信息重点讲解searchAnalyzer和analyzer<span>searchAnalyzer</span>
表示的是查询时候该单词如何分词<span>analyzer</span>
表示的是索引(保存)的时候如何分词@Filed
中的type
表示的是该字段类型,重点强调下时间类型type = FieldType.Date
LocalDate
那么format=DateFormat.date
LocalDateTime
,使用format = DateFormat.date_time
其作用有主要有 2 个
当然我个人认为其存在几个缺点
Contains
,而应该使用Eqauls
【后面会谈到】关键接口是:CrudRepository
和PagingAndSortingRepository
CrudRepository
集成了基本的 CRUD,如下图所示PagingAndSortingRepository
在CrudRepository
的基础上定义了**分页和排序 **操作。使用的时候,可以直接使用带分页的PagingAndSortingRepository
public interface BookEsMapper extends PagingAndSortingRepository<Book, String> {
}
比如定义了上述接口,并且在配置类获取启动类上添加了注解@EnableElasticsearchRepositories(basePackages = "club.hicode.dockerhi")
那么就可以使用了,下面给出一个插入的代码
@Test
public void testBookSave() {
Book book = new Book();
book.setName("Kotlin开发手册");
book.setAuthor("文在寅");
book.setId("012");
book.setPublishDate(LocalDate.now());
book.setPublishDateTime(LocalDateTime.now());
Book result = bookEsMapper.save(book);
System.out.println(result);
}
@Test
public void testBaseApi() {
Optional<Book> optBook = bookEsMapper.findById("012");
optBook.ifPresent(System.out::println);
Iterable<Book> all = bookEsMapper.findAll();
all.forEach(System.out::println);
bookEsMapper.deleteById("012");
System.out.println("删除 ok");
}
执行成功后,通过 DevTools
的指令 GET /book
可以查看到如下信息
{
"book" : {
"aliases" : { },
"mappings" : {
"properties" : {
"_class" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"author" : {
"type" : "text",
"analyzer" : "ue-ngram"
},
"id" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "text",
"analyzer" : "ik_max_word",
"search_analyzer" : "ik_smart"
},
"publishDate" : {
"type" : "date",
"format" : "date"
},
"publishDateTime" : {
"type" : "date",
"format" : "date_time"
}
}
},
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "1",
"provided_name" : "book",
"creation_date" : "1611655951204",
"analysis" : {
"filter" : {
"my_pinyin" : {
"keep_joined_full_pinyin" : "true",
"lowercase" : "true",
"none_chinese_pinyin_tokenize" : "false",
"keep_original" : "true",
"keep_none_chinese_together" : "true",
"keep_first_letter" : "true",
"trim_whitespace" : "true",
"type" : "pinyin",
"keep_none_chinese" : "true",
"keep_full_pinyin" : "false"
}
},
"char_filter" : {
"ue_char_filter" : {
"type" : "mapping",
"mappings" : [
"- => ,",
"— => ,"
]
}
},
"analyzer" : {
"ue_ik_pinyin_analyzer" : {
"filter" : [
"my_pinyin"
],
"char_filter" : [
"html_strip",
"ue_char_filter"
],
"type" : "custom",
"tokenizer" : "ik_max_word"
},
"ue-ngram" : {
"type" : "custom",
"char_filter" : [
"html_strip",
"ue_char_filter"
],
"tokenizer" : "ngram_tokenizer"
}
},
"tokenizer" : {
"ngram_tokenizer" : {
"token_chars" : [
"letter",
"digit"
],
"min_gram" : "2",
"type" : "ngram",
"max_gram" : "3"
}
}
},
"number_of_replicas" : "1",
"uuid" : "ipVtuyH6Qsy422WWQ39gQw",
"version" : {
"created" : "7100199"
}
}
}
}
}
描述下 settings
的内容就是上文代码中@Setting(settingPath = "es/es-setting.json")
设置中的内容。
下面给出实例代码
public interface BookEsMapper extends PagingAndSortingRepository<Book, String> {
List<Book> findByAuthorContains(String author);
List<Book> findByAuthorEquals(String author);
List<Book> findByNameContaining(String name);
List<Book> findByNameEquals(String name);
}
当我们调用这些代码的时候,为了更方便的进行调试和展示 Query语句,建议在配置文件application.properties
添加
logging.level.tracer=TRACE
个人不建议使用 在中文语义下使用 JPA 进行Text的查询,因为这其实挺让人迷糊的,我在学习的时候踩了不少坑。
举个例子:
Book
类中定义了 name
字段的索引分词是 ik_max_word
,检索分词用的是 ik_smart
。
对于kotlin 开发手册
,索引的时候分词为:kotlin
/开发
/手册
但是如果使用findByNameContaining("发手")
的时候,虽然在语义上是发手
是包含于开发手册
,但是因为分词的缘故,检索不到。
综上,个人建议 JPA检索上的使用更应该是基于 Term
的查询和英文检索
。新增、修改、删除是没有问题的。
本文主要是 2 个点: