# SpringBoot整合Elasticsearch初体验

# 1.添加maven依赖

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.6.RELEASE</version>
		<relativePath /> 
	</parent>
	
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 2.application.yml

spring:
  application:
    name: senta-es
  data:
    elasticsearch:
      cluster-name: elasticsearch  #es默认集群名字
      cluster-nodes: 122.51.226.121:9300  #9200是图形界面端,9300代码端
      repositories:
        enabled: true   #开启 Elasticsearch 仓库(默认值:true)
      properties:
        transport:
          tcp:
            connect_timeout: 120s  # ES设置连接超时时间
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.实体类层


import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

/**
 * 对应的实体类
 * @author 福小林
 *
 * 注解说明
 * Document 对应一个文档数据 indexName 索引名称  type 类型
 */
@Document(indexName = "myIndexName", type = "user")
@Data
public class UserEntity {
    @Id
    private String id;
    private String name;
    private int sex;
    private int age;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 4.Dao类层

import com.senta.elasticsearch.entity.UserEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

/**
 * @author 福小林
 * 操作对应es的数据层
 */
@Repository
public interface UserRepository  extends CrudRepository<UserEntity, String> {

}

1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.Controller层


import com.senta.elasticsearch.entity.UserEntity;
import com.senta.elasticsearch.mapper.xml.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

/**
 * @author 福小林
 * 操作es的controller
 */
@RestController
public class EsController {

    @Autowired
    private UserRepository userRepository;

    @RequestMapping("/addUser")
    public UserEntity addUser(@RequestBody UserEntity user) {
        return userRepository.save(user);
    }

    @RequestMapping("/findUser")
    public Optional<UserEntity> findUser(String id) {
        return userRepository.findById(id);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 6.启动项目

@SpringBootApplication
public class ESApplication {

	public static void main(String[] args) {
		SpringApplication.run(ESApplication.class, args);
	}
}
1
2
3
4
5
6
7

# 7.若扫描Repostitory失败

/**
 * @author 福小林
 * 若扫描UserRepository失败,则需要添加E@nableElasticsearchRepositories
 */
@SpringBootApplication
@EnableElasticsearchRepositories(basePackages = "com.senta.repository")
public class ESApplication {

	public static void main(String[] args) {
		SpringApplication.run(ESApplication.class, args);
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13

# 8.结合DSL语句整合

# 8.1 常用dsl语句汇总

# 类似于mysql查询语句 SELECT * FROM billingitemdis WHERE orderDoctor='汪琳休' AND  patientName='聂炎' AND itemClass1 !='E' AND orderDoctorId='12884' limit  0,308 ORDEY BY pk ASC
GET billing/billingitemdis/_search
{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "orderDoctor":"汪琳休"
                    }
                },
                {
                    "match":{
                        "patientName":"聂炎"
                    }
                }
            ],
            "must_not":[
                {
                    "match":{
                        "itemClass1":"E"
                    }
                }
            ],
            "should":[
                {
                    "match":{
                        "hosOutp":"住院"
                    }
                },
                {
                    "match":{
                        "itemClass2":"治疗"
                    }
                }
            ],
            "filter":{
                "term":{
                    "orderDoctorId":"12884"
                }
            }
        }
    },
    "sort":[
        {
            "pk":{
                "order":"asc"
            }
        }
    ],
    "size":308,
    "from":0
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

查询语句需要对应的顺序以上覆盖了大部分常用的顺序,当在java代码中创建应该遵循以上的顺序和层次结构,不然都有报错的可能

# 8.2 具体参数说明

# query
最外层查询结构

#  bool
可以添加:must,must_not, should, filter

# must

可以通过match匹配多个条件,要求每个条件必须存在才可以查询到

## must_not
可以通过match匹配,符合条件的会被过滤掉

#should
可以通过match匹配多个条件,每个match的相关度计算一致,需要调整相关度可在should中添加bool作刺激匹配,项匹配的数据按相关度_score排序

# filter
过滤,通过term来精准过滤条件,全字仅匹配成功的才通过

# sort desc排序
排序,可以省写 "sort": "pk" 

# size
显示当前页数据条数,ES有默认的大小可以通过 _settings设置,当显示不出全部数据时可能是页数限制

# from
当前页,从 0 开始,由于ES的特性,在第一页返回的是最快的,访问数据时间页深度增加而增加,不建议深分页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 8.3 对应上面的dsl的java代码

@GetMapping("/query")
public Page<BillingItemDis> queryFromEs(){

    NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    MatchQueryBuilder matchOderDoctor = QueryBuilders.matchQuery("orderDoctor", "汪琳休");
    MatchQueryBuilder matchPatientName = QueryBuilders.matchQuery("patientName", "聂炎");

    boolQuery.must(matchOderDoctor);
    boolQuery.must(matchPatientName);

    MatchQueryBuilder matchItemClass1 = QueryBuilders.matchQuery("itemClass1","E");
    boolQuery.mustNot(matchItemClass1);

    MatchQueryBuilder matchHosOutp = QueryBuilders.matchQuery("hosOutp", "住院");
    MatchQueryBuilder matchItemClass2 = QueryBuilders.matchQuery("itemClass2", "治疗");
    boolQuery.should(matchHosOutp);
    boolQuery.should(matchItemClass2);


    TermQueryBuilder termOrderDoctorId = QueryBuilders.termQuery("orderDoctorId", "12884");
    boolQuery.filter(termOrderDoctorId);

    builder.withQuery(boolQuery);

    builder.withSort(SortBuilders.fieldSort("pk").order(SortOrder.DESC));

    builder.withPageable(PageRequest.of(0,308));

    NativeSearchQuery searchQuery = builder.build();
    
    Page<BillingItemDis> search = billingItemDisRepository.search(searchQuery);

    return search;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 8.4 字段定义规范

Text:文本文件,会被分词,直接term就无法匹配,保存为string,不支持range,
Integer:基本数据类型
Long: 基本数据类型
Date: 日期类型,可通过format进行副值定义,建议需要进行日期筛选时使用
Float:单精度
Double: 双精度
Boolean :
Object: 对象类型
Auto: 自动,不使用
Nested: 嵌套对象数据类型,会形成特定的关联关系,更新关联父子对象时会更新整个数据库的父子,使用与查询多,偶尔更新的场景
Ip: 保存ip地址时使用
Attachment:附件类型,doc,xml
Keyword:关键词,默认不分词,可以完全匹配,要求姓名必须有keyword字段

DateFormat:日期类型对应的其他格式请参考 http://www.kyjszj.com/htzq/109.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上次更新: 2020-7-11 0:26:35