文章目录
- 一、SpringBoot操作ElasticSearch前期准备工作
- 二、SpringBoot增删改查ElasticSearch
- 1.新增修改
- 2.删除
- 3.查询
- 三、ElasticSearch中的过滤查询
- 1.概念介绍
- 2.过滤语法
- 3.常见的过滤器类型
- ① term filter
- ② terms filter
- ③ ranage filter
- ④ exists filter
- ⑤ ids filter
一、SpringBoot操作ElasticSearch前期准备工作
1.先在pom.xml里面引入依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.然后在SpringBoot项目中增加以下配置。
这里我是用HTTP的方式进行连接,端口是9200。如果你们是用TCP方式进行连接的话,端口记得改成9300。
@Configuration
public class ESRestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("127.0.0.1:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
3.编写要创建索引和类型的实体。
记得生成getter和setter方法哦。
@Document
: 代表一个文档记录,使用此注解项目启动后自动创建索引和类型
indexName
: 用来指定索引名称
type
: 用来指定索引类型
@Id
: 用来将对象中id和ES中_id映射
@Field
: 用来指定ES中的字段对应Mapping
type
: 用来指定ES中存储类型
analyzer
: 用来指定使用哪种分词器
@Document(indexName = "online_house_achieve", type = "house")
public class House {
@Id
private Long id; //房屋id
private String coverPhoto; //封面图片
private String ownerShip; //房本图片
private BigDecimal money; //租金(元/月)
// @Field(type = FieldType.Text, analyzer ="ik_max_word")
private String houseType; //户型
private BigDecimal area; //面积
// @Field(type = FieldType.Keyword)
private String orientation; //朝向
// @Field(type = FieldType.Text, analyzer ="ik_max_word")
private String floor; //楼层
private String renovation; //装修
private Integer category; //房屋出售种类
// @Field(type = FieldType.Text, analyzer ="ik_max_word")
private String location; //房屋位置
// @Field(type = FieldType.Text, analyzer ="ik_max_word")
private String info; //房屋简介
// @Field(type = FieldType.Text, analyzer ="ik_max_word")
private String details; //房屋详情
private Long userId; //房屋所属中介id
// @Field(type = FieldType.Object)
private User user; //房屋所属中介
private Date createTime; //创建时间
// @Field(type = FieldType.Date)
private Date updateTime; //更新时间
private Integer state; //房屋状态
4.编写Repository接口。
public interface HouseRepository extends ElasticsearchRepository<House,String> {
}
5.启动类上加上Repository接口扫描。
@SpringBootApplication
@EnableElasticsearchRepositories(basePackages = "com.wx.programmer.repository")
public class OnlineHouseAchieve
{
public static void main( String[] args )
{
SpringApplication.run(OnlineHouseAchieve.class, args);
}
}
这样前期准备工作就完成了~
二、SpringBoot增删改查ElasticSearch
1.新增修改
Tips:如果传id的话,id在ES中存在则修改更新数据,如果id在ES中不存在,则新增数据。如果不传id,则新增一条_id随机的数据。
使用spring-data-elasticsearch完成新增修改操作:
@Test
public void testSaveOrUpdate() {
House house = new House();
house.setId(1L);
house.setUpdateTime(new Date());
house.setInfo("中装一室一厅,楼层好,采光足,稀缺房源");
house.setDetails("半径200米内有:工商银行,建设银行,农业银行,邮电局,中国电信,民航总医院,朝阳区第二医院,小庄医院,易出莲花,华堂商场,京客隆,法宝超市,苏宁电器,国美电器,郭林家常菜,肯德基,麦当劳,必胜客等多家餐厅,北京纺织技术学校,甘露园小学。");
houseRepository.save(house);
}
使用RestHighLevelClient完成新增修改操作:
IndexRequest request = new IndexRequest("online_house_achieve", "house");
request.id("1");
request.source(JSONObject.toJSONString(house), XContentType.JSON);
IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
logger.info("操作结果:" + response.getResult());
2.删除
使用spring-data-elasticsearch完成删除操作:
@Test
public void testDelete(){
House house = new House();
house.setId(1L);
houseRepository.delete(house);
}
使用RestHighLevelClient完成删除操作:
DeleteRequest request = new DeleteRequest("online_house_achieve", "house", "1");
DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
logger.info("操作结果:" + response.getResult());
3.查询
使用spring-data-elasticsearch完成查询操作:
Keyword | Sample | Elasticsearch Query String |
---|---|---|
And | findByNameAndPrice | {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or | findByNameOrPrice | {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is | findByName | {"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not | findByNameNot | {"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between | findByPriceBetween | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
LessThanEqual | findByPriceLessThan | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
GreaterThanEqual | findByPriceGreaterThan | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After | findByPriceAfter | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like | findByNameLike | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith | findByNameEndingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
Contains/Containing | findByNameContaining | {"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}} |
In | findByNameIn (Collection<String>names) | {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn | findByNameNotIn (Collection<String>names) | {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
Near | findByStoreNear | Not Supported Yet ! |
True | findByAvailableTrue | {"bool" : {"must" : {"field" : {"available" : true}}}} |
False | findByAvailableFalse | {"bool" : {"must" : {"field" : {"available" : false}}}} |
OrderBy | findByAvailable TrueOrderByNameDesc | {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}} |
spring-data-elasticsearch操作方式有很多种,我们这里举例演示一种,其他的根据上面表格内容举一反三~
1.根据houseType字段和orientation字段查询数据:
public interface HouseRepository extends ElasticsearchRepository<House,String> {
// 根据户型和朝向查询
List<House> findByHouseTypeAndOrientation(String houseType, String orientation);
}
@Test
public void testESSearch(){
List<House> result = houseRepository.findByHouseTypeAndOrientation("两室一厅一卫", "南");
logger.info("查询结果:{}", JSONObject.toJSONString(result));
}
使用RestHighLevelClient完成查询操作:
RestHighLevelClient操作方式有很多种,我们这里举例演示几种,其他的根据上面表格内容举一反三~
1.根据id降序排序,然后获取前两个数据。
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(0).size(2).sort("id", SortOrder.DESC).query(QueryBuilders.matchAllQuery());
searchRequest.indices("online_house_achieve").types("house").source(sourceBuilder);
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = search.getHits().getHits();
for (SearchHit hit : hits) {
logger.info(hit.getSourceAsString());
}
2.高亮查询,查询orientation字段值为“南”的文档数据,并高亮展示。
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("orientation").preTags("<span style='color:red;'>").postTags("</span>");
sourceBuilder.highlighter(highlightBuilder).
query(QueryBuilders.termQuery("orientation","南"));
searchRequest.indices("online_house_achieve").types("house").source(sourceBuilder);
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = search.getHits().getHits();
for (SearchHit hit : hits) {
logger.info(hit.getSourceAsString());
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
highlightFields.forEach((k,v)-> logger.info("key: "+k + " value: "+v.fragments()[0]));
}
3.布尔查询,查询出money字段值在2500~2700之间的数据或者category字段值为2的文档数据:
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
RangeQueryBuilder rangeQueryBuilder = QueryBuilders
.rangeQuery("money").from(2500).to(2700);
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("category", 2);
boolQueryBuilder.should(termQueryBuilder).should(rangeQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.indices("online_house_achieve").types("house").source(searchSourceBuilder);
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = search.getHits().getHits();
for (SearchHit hit : hits) {
logger.info(hit.getSourceAsString());
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
highlightFields.forEach((k,v)-> logger.info("key: "+k + " value: "+v.fragments()[0]));
}
4.布尔查询,将上面代码改造,只查询出money字段值在2500~2700之间的数据:
boolQueryBuilder.should(termQueryBuilder).must(rangeQueryBuilder);
5.布尔查询,将上面代码改造,只查询出category字段值不为2的并且money字段值在2500~2700之间的文档数据。
boolQueryBuilder.mustNot(termQueryBuilder).must(rangeQueryBuilder);
三、ElasticSearch中的过滤查询
1.概念介绍
其实准确来说,ES中的查询操作分为2种: 查询(query)
和过滤(filter)
。查询即是之前提到的query查询,它 (查询)默认会计算每个返回文档的得分,然后根据得分排序
。而过滤(filter)只会筛选出符合的文档,并不计算得分,且它可以缓存文档 。所以,单从性能考虑,过滤比查询更快
。
有关查询的用法,请浏览博客:ElasticSearch6.x版本概念介绍及Kibana操作的增删改查常用API
换句话说,过滤适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时, 应先使用过滤操作过滤数据, 然后使用查询匹配数据。
具体流程看下图:
2.过滤语法
GET /online_house_achieve/house/_search
{
"query": {
"bool": {
"must": [
{"match_all": {}}
],
"filter": {
"range": {
"id": {
"gte": 5,
"lte": 8
}
}
}
}
}
}
在执行filter和query时,先执行filter在执行query。
ElasticSearch会自动缓存经常使用的过滤器,以加快性能。
3.常见的过滤器类型
① term filter
先过滤出category字段为2的文档数据,然后再从过滤出来的文档数据中查询orientation字段为 “东” 的文档数据:
GET /online_house_achieve/house/_search
{
"query": {
"bool": {
"must": [
{"term": {
"orientation": {
"value": "东"
}
}}
],
"filter": {
"term": {
"category": 2
}
}
}
}
}
② terms filter
先过滤出category字段为1或2的文档数据,然后再从过滤出来的文档数据中查询orientation字段为 “东” 的文档数据:
GET /online_house_achieve/house/_search
{
"query": {
"bool": {
"must": [
{"term": {
"orientation": {
"value": "东"
}
}}
],
"filter": {
"terms": {
"category":[
1,2
]
}
}
}
}
}
③ ranage filter
先过滤出id字段值在5~8之间的文档数据,然后再从过滤出来的文档数据中查询orientation字段为 “东” 的文档数据:
GET /online_house_achieve/house/_search
{
"query": {
"bool": {
"must": [
{"term": {
"orientation": {
"value": "东"
}
}}
],
"filter": {
"range": {
"id": {
"gte": 5,
"lte": 8
}
}
}
}
}
}
④ exists filter
先过滤出id字段存在的文档数据,然后再从过滤出来的文档数据中查询orientation字段为 “东” 的文档数据:
GET /online_house_achieve/house/_search
{
"query": {
"bool": {
"must": [
{"term": {
"orientation": {
"value": "东"
}
}}
],
"filter": {
"exists": {
"field": "id"
}
}
}
}
}
⑤ ids filter
先过滤出id字段值为5或8的文档数据,然后再从过滤出来的文档数据中查询orientation字段为 “东” 的文档数据:
GET /online_house_achieve/house/_search
{
"query": {
"bool": {
"must": [
{"term": {
"orientation": {
"value": "东"
}
}}
],
"filter": {
"ids": {
"values": [5, 8]
}
}
}
}
}