Skip to content

Commit e7534bc

Browse files
authored
Create README.md
1 parent 9f2bf47 commit e7534bc

File tree

1 file changed

+318
-0
lines changed

1 file changed

+318
-0
lines changed

springboot-elasticsearch/README.md

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
# SpringBoot整合Elasticsearch+IK
2+
3+
支持作者就star一下,谢谢 🎉🎉
4+
5+
ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。
6+
7+
Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
8+
9+
**安装相关软件**
10+
| 软件名称 | 软件版本 | 下载地址 |
11+
|:--|:--|:--|
12+
| Elasticsearch | 6.2.4 |[elasticsearch官网下载](https://www.elastic.co/cn/downloads/past-releases) |
13+
| IK中文分词器| 6.2.4 |[ik分词器官网下载](https://github.com/medcl/elasticsearch-analysis-ik/releases) |
14+
| kibana| 6.2.4 |[kibana官网下载](https://www.elastic.co/cn/downloads/past-releases) |
15+
16+
>如果实在找不到,那么群文件夹:957406675
17+
18+
安装分词插件,分别解压下载好的三个文件,然后解压IK,复制到`elasticsearch`安装目录下的plugins文件夹中。
19+
20+
运行`elasticsearch/bin/elasticsearch.bat`文件,浏览器访问: http://localhost:9200/ 会得到相应的版本信息,如:
21+
```json
22+
{
23+
"name": "Bb-td48",
24+
"cluster_name": "elasticsearch",
25+
"cluster_uuid": "_IM0iQAeToWALU0tq7rsZQ",
26+
"version": {
27+
"number": "6.2.4",
28+
"build_hash": "ccec39f",
29+
"build_date": "2018-04-12T20:37:28.497551Z",
30+
"build_snapshot": false,
31+
"lucene_version": "7.2.1",
32+
"minimum_wire_compatibility_version": "5.6.0",
33+
"minimum_index_compatibility_version": "5.0.0"
34+
},
35+
"tagline": "You Know, for Search"
36+
}
37+
```
38+
然后再运行`kibana/bin/kibana.bat`文件,浏览器访问:http://localhost:5601 ,可以看到kibana的控制台页面。
39+
40+
到此相关软件安装完成,下面开始springboot整合elasticsearch。
41+
# 开始整合
42+
依赖
43+
```xml
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
47+
</dependency>
48+
还有lombok,自己加一下
49+
```
50+
application.yml
51+
```yml
52+
spring:
53+
data:
54+
elasticsearch:
55+
cluster-name: elasticsearch
56+
cluster-nodes: 127.0.0.1:9300
57+
```
58+
实体类
59+
```java
60+
@Data
61+
@AllArgsConstructor
62+
@NoArgsConstructor
63+
@Document(indexName = "item", type = "docs", shards = 1, replicas = 0)
64+
public class Item {
65+
@Id
66+
private Long id;
67+
68+
@Field(type = FieldType.Text, analyzer = "ik_max_word")
69+
private String title; //标题
70+
71+
@Field(type = FieldType.Keyword)
72+
private String category;// 分类
73+
74+
@Field(type = FieldType.Keyword)
75+
private String brand; // 品牌
76+
77+
@Field(type = FieldType.Double)
78+
private Double price; // 价格
79+
80+
@Field(index = false, type = FieldType.Keyword)
81+
private String images; // 图片地址
82+
}
83+
```
84+
Spring Data通过注解来声明字段的映射属性,有下面的三个注解:
85+
86+
- `@Document` 作用在类,标记实体类为文档对象,一般有两个属性
87+
- indexName:对应索引库名称
88+
- type:对应在索引库中的类型
89+
- shards:分片数量,默认5
90+
- replicas:副本数量,默认1
91+
- `@Id` 作用在成员变量,标记一个字段作为id主键
92+
- `@Field` 作用在成员变量,标记为文档的字段,并指定字段映射属性:
93+
- type:字段类型,是是枚举:FieldType
94+
- index:是否索引,布尔类型,默认是true
95+
- store:是否存储,布尔类型,默认是false
96+
- analyzer:分词器名称
97+
98+
repository
99+
```java
100+
public interface ItemRepository extends ElasticsearchRepository<Item, Long> {
101+
102+
/**
103+
* 根据价格区间查询
104+
*
105+
* @param price1
106+
* @param price2
107+
* @return
108+
*/
109+
List<Item> findByPriceBetween(double price1, double price2);
110+
}
111+
```
112+
**下面的测试类是重点**
113+
```java
114+
@RunWith(SpringRunner.class)
115+
@SpringBootTest
116+
public class SpringbootElasticsearchApplicationTests {
117+
118+
@Autowired
119+
private ElasticsearchTemplate elasticsearchTemplate;
120+
121+
@Autowired
122+
private ItemRepository itemRepository;
123+
124+
/**
125+
* 创建索引
126+
*/
127+
@Test
128+
public void createIndex() {
129+
// 创建索引,会根据Item类的@Document注解信息来创建
130+
elasticsearchTemplate.createIndex(Item.class);
131+
// 配置映射,会根据Item类中的id、Field等字段来自动完成映射
132+
elasticsearchTemplate.putMapping(Item.class);
133+
}
134+
135+
/**
136+
* 删除索引
137+
*/
138+
@Test
139+
public void deleteIndex() {
140+
elasticsearchTemplate.deleteIndex("item");
141+
}
142+
143+
/**
144+
* 新增
145+
*/
146+
@Test
147+
public void insert() {
148+
Item item = new Item(1L, "小米手机7", "手机", "小米", 2999.00, "https://img12.360buyimg.com/n1/s450x450_jfs/t1/14081/40/4987/124705/5c371b20E53786645/c1f49cd69e6c7e6a.jpg");
149+
itemRepository.save(item);
150+
}
151+
152+
/**
153+
* 批量新增
154+
*/
155+
@Test
156+
public void insertList() {
157+
List<Item> list = new ArrayList<>();
158+
list.add(new Item(2L, "坚果手机R1", "手机", "锤子", 3999.00, "https://img12.360buyimg.com/n1/s450x450_jfs/t1/14081/40/4987/124705/5c371b20E53786645/c1f49cd69e6c7e6a.jpg"));
159+
list.add(new Item(3L, "华为META20", "手机", "华为", 4999.00, "https://img12.360buyimg.com/n1/s450x450_jfs/t1/14081/40/4987/124705/5c371b20E53786645/c1f49cd69e6c7e6a.jpg"));
160+
list.add(new Item(4L, "iPhone X", "手机", "iPhone", 5100.00, "https://img12.360buyimg.com/n1/s450x450_jfs/t1/14081/40/4987/124705/5c371b20E53786645/c1f49cd69e6c7e6a.jpg"));
161+
list.add(new Item(5L, "iPhone XS", "手机", "iPhone", 5999.00, "https://img12.360buyimg.com/n1/s450x450_jfs/t1/14081/40/4987/124705/5c371b20E53786645/c1f49cd69e6c7e6a.jpg"));
162+
// 接收对象集合,实现批量新增
163+
itemRepository.saveAll(list);
164+
}
165+
166+
/**
167+
* 修改
168+
*
169+
* :修改和新增是同一个接口,区分的依据就是id,这一点跟我们在页面发起PUT请求是类似的。
170+
*/
171+
172+
/**
173+
* 删除所有
174+
*/
175+
@Test
176+
public void delete() {
177+
itemRepository.deleteAll();
178+
}
179+
180+
/**
181+
* 基本查询
182+
*/
183+
@Test
184+
public void query() {
185+
// 查询全部,并按照价格降序排序
186+
Iterable<Item> items = itemRepository.findAll(Sort.by("price").descending());
187+
items.forEach(item -> System.out.println("item = " + item));
188+
}
189+
190+
/**
191+
* 自定义方法
192+
*/
193+
@Test
194+
public void queryByPriceBetween() {
195+
// 根据价格区间查询
196+
List<Item> list = itemRepository.findByPriceBetween(5000.00, 6000.00);
197+
list.forEach(item -> System.out.println("item = " + item));
198+
}
199+
200+
/**
201+
* 自定义查询
202+
*/
203+
@Test
204+
public void search() {
205+
// 构建查询条件
206+
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
207+
// 添加基本分词查询
208+
queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米手机"));
209+
// 搜索,获取结果
210+
Page<Item> items = itemRepository.search(queryBuilder.build());
211+
// 总条数
212+
long total = items.getTotalElements();
213+
System.out.println("total = " + total);
214+
items.forEach(item -> System.out.println("item = " + item));
215+
}
216+
217+
/**
218+
* 分页查询
219+
*/
220+
@Test
221+
public void searchByPage() {
222+
// 构建查询条件
223+
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
224+
// 添加基本分词查询
225+
queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
226+
// 分页:
227+
int page = 0;
228+
int size = 2;
229+
queryBuilder.withPageable(PageRequest.of(page, size));
230+
// 搜索,获取结果
231+
Page<Item> items = itemRepository.search(queryBuilder.build());
232+
long total = items.getTotalElements();
233+
System.out.println("总条数 = " + total);
234+
System.out.println("总页数 = " + items.getTotalPages());
235+
System.out.println("当前页:" + items.getNumber());
236+
System.out.println("每页大小:" + items.getSize());
237+
items.forEach(item -> System.out.println("item = " + item));
238+
}
239+
240+
/**
241+
* 排序
242+
*/
243+
@Test
244+
public void searchAndSort() {
245+
// 构建查询条件
246+
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
247+
// 添加基本分词查询
248+
queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
249+
// 排序
250+
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
251+
// 搜索,获取结果
252+
Page<Item> items = this.itemRepository.search(queryBuilder.build());
253+
// 总条数
254+
long total = items.getTotalElements();
255+
System.out.println("总条数 = " + total);
256+
items.forEach(item -> System.out.println("item = " + item));
257+
}
258+
259+
/**
260+
* 聚合为桶
261+
*/
262+
@Test
263+
public void testAgg() {
264+
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
265+
// 不查询任何结果
266+
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
267+
// 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
268+
queryBuilder.addAggregation(AggregationBuilders.terms("brands").field("brand"));
269+
// 2、查询,需要把结果强转为AggregatedPage类型
270+
AggregatedPage<Item> aggPage = (AggregatedPage<Item>) itemRepository.search(queryBuilder.build());
271+
// 3、解析
272+
// 3.1、从结果中取出名为brands的那个聚合,
273+
// 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
274+
StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
275+
// 3.2、获取桶
276+
List<StringTerms.Bucket> buckets = agg.getBuckets();
277+
// 3.3、遍历
278+
for (StringTerms.Bucket bucket : buckets) {
279+
// 3.4、获取桶中的key,即品牌名称
280+
System.out.println(bucket.getKeyAsString());
281+
// 3.5、获取桶中的文档数量
282+
System.out.println(bucket.getDocCount());
283+
}
284+
}
285+
286+
/**
287+
* 嵌套聚合,求平均值
288+
*/
289+
@Test
290+
public void testSubAgg() {
291+
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
292+
// 不查询任何结果
293+
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
294+
// 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
295+
queryBuilder.addAggregation(
296+
AggregationBuilders.terms("brands").field("brand")
297+
.subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶内进行嵌套聚合,求平均值
298+
);
299+
// 2、查询,需要把结果强转为AggregatedPage类型
300+
AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
301+
// 3、解析
302+
// 3.1、从结果中取出名为brands的那个聚合,
303+
// 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
304+
StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
305+
// 3.2、获取桶
306+
List<StringTerms.Bucket> buckets = agg.getBuckets();
307+
// 3.3、遍历
308+
for (StringTerms.Bucket bucket : buckets) {
309+
// 3.4、获取桶中的key,即品牌名称 3.5、获取桶中的文档数量
310+
System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "");
311+
312+
// 3.6.获取子聚合结果:
313+
InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
314+
System.out.println("平均售价:" + avg.getValue());
315+
}
316+
}
317+
}
318+
```

0 commit comments

Comments
 (0)