elk 三

微信图片_20221230153659.jpg

ELK

索引 Index

索引管理

直接put数据es会自动生成索引,并建立动态映射dynamic mapping

创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT /my_index
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"field1":{
"type": "text"
},
"field2":{
"type": "text"
}
}
},
"aliases": {
"default_index": {}
}
}

查询索引

1
2
3
GET /my_index/_mapping

GET /my_index/_setting

修改索引

1
2
3
4
5
6
PUT /my_index/_settings
{
"index" : {
"number_of_replicas" : 2
}
}

修改副本数为2

删除索引

1
2
3
4
5
6
7
DELETE /my_index

DELETE /index_one,index_two

DELETE /index_*

DELETE /_all
  • 防止恶意删除索引,删除时必须指定索引名

修改配置文件elasticsearch.yml

1
action.destructive_requires_name: true

定制分词器

默认分词器

standard tokenizer:以单词边界进行切分

standard token filter:什么都不做

lowercase token filter:将所有字母转换为小写

stop token filer(默认被禁用):移除停用词

修改分词器

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"es_std":{
"type":"standard",
"stopwords":"_english_"
}
}
}
}
}
  • test
1
2
3
4
5
6
7
8
9
10
11
GET /my_index/_analyze
{
"analyzer": "standard",
"text": "a dog is in the house"
}

GET /my_index/_analyze
{
"analyzer": "es_std",
"text": "a dog is in the house"
}

type底层结构

type

type,是一个index中用来区分类似的数据的

在底层的lucene中建立索引的时候,全部是opaque bytes类型,不区分类型的,lucene是没有type的概念的,在document中,实际上将type作为一个document的field来存储,即_type,es通过_type来进行type的过滤和筛选

type弃用

同一索引下,不同type的数据存储其他type的field 大量空值,造成资源浪费

不同类型数据,要放到不同的索引中

es9中,彻底删除type

定制dynamic mapping

dynamic策略

true:遇到陌生字段,就进行dynamic mapping

false:新检测到的字段将被忽略,这些字段将不会被索引,因此将无法搜索,但仍将出现在返回点击的源字段中,这些字段不会添加到映射中,必须显式添加新字段

strict:遇到陌生字段,就报错

date_detection日期探测

默认会按照一定格式识别date,例如yyyy-MM-dd。如果某个field先过来一个2022-12-30的值,就会被自动dynamic mapping成date,后面如果再来一个”hello world”之类的值,就会报错,可以手动关闭某个type的date_detection,如果有需要,自己手动指定某个field为date类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT /my_index
{
"mappings": {
"date_detection": false,
"properties": {
"title": {
"type": "text"
},
"address": {
"type": "object",
"dynamic": "true"
}
}
}
}

自定义日期格式

1
2
3
4
5
6
PUT my_index
{
"mappings": {
"dynamic_date_formats": ["MM/dd/yyyy"]
}
}

numeric_detection 数字探测

json支持本机浮点和整数数据类型,但某些应用程序或语言有时可能将数字呈现为字符串

1
2
3
4
5
6
PUT my_index
{
"mappings": {
"numeric_detection": true
}
}

零停机重建索引

一个field的设置是不能被修改的,如果要修改一个Field,那么应该重新按照新的mapping,建立一个index,然后将数据批量查询出来,重新用bulk api写入index中

零停机过程

  • 此时想修改title的类型,会报错,因为不允许被修改

  • 重新建立一个索引,将旧索引的数据查询出来,再导入新索引

  • 这个时候给旧索引起一个别名,我们将就索引中的数据通过scroll api查询出来,使用bulk api将scoll查出来的一批数据,批量写入新索引,并给新索引起一个别名

  • 我们这个时候只需要切换读取到新索引的别名即可,应用会直接通过index别名使用新的索引中的数据,应用程序不需要停机,零提交,高可用

中文分词器 IK分词器

IK分词器的安装

下载地址https://github.com/medcl/elasticsearch-analysis-ik/releases

下载后解压到 es/plugins/ik中,重启es即可

IK分词器基础

ik_max_word: 会将文本做最细粒度的拆分,会穷尽各种可能的组合

ik_smart: 会做最粗粒度的拆分

IK分词器的使用

1
2
3
4
5
6
7
8
9
10
11
12
PUT /my_index
{
"mappings": {
"properties": {
"text":{
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
}

存储时,使用ik_max_word

搜索时,使用ik_smart

IK配置文件

ik配置文件地址:es/plugins/ik/config

IKAnalyzer.cfg.xml:用来配置自定义词库

main.dic:ik原生内置的中文词库,总共有27万多条,只要是这些单词,都会被分在一起

preposition.dic: 介词

quantifier.dic:放了一些单位相关的词,量词

suffix.dic:放了一些后缀

surname.dic:中国的姓氏

stopword.dic:英文停用词

main.dic:包含了原生的中文词语,会按照这个里面的词语去分词

stopword.dic:包含了英文的停用词

自定义词库

修改IKAnalyzer.cfg.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">my.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

创建my.dic文件,补充词句重启即可

mysql热更新 词库

源码下载https://github.com/medcl/elasticsearch-analysis-ik/releases

配置相关请转自下面链接查看

IK 使用mysql热更新 词库https://blog.csdn.net/qq_45315629/article/details/128493563?spm=1001.2014.3001.5501

Java实现索引管理

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package com.dream.xiaobo;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

/**
* @author xiaobo
* @date 2022/11/23 - 13:19
*/
@SpringBootTest(classes = ElasticsearchSpringBootApplication.class)
@RunWith(SpringRunner.class)
public class TestIndex {

@Autowired
private RestHighLevelClient client;

/**
* 创建索引对象
*/
@Test
public void testCreateIndex() throws IOException {

CreateIndexRequest createIndexRequest = new CreateIndexRequest("wyb_index");

createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));

//指定映射1
createIndexRequest.mapping(" {\n" +
" \t\"properties\": {\n" +
" \"name\":{\n" +
" \"type\":\"keyword\"\n" +
" },\n" +
" \"description\": {\n" +
" \"type\": \"text\"\n" +
" },\n" +
" \"price\":{\n" +
" \"type\":\"long\"\n" +
" },\n" +
" \"pic\":{\n" +
" \"type\":\"text\",\n" +
" \"index\":false\n" +
" }\n" +
" \t}\n" +
"}", XContentType.JSON);

//指定映射2

// Map<String, Object> message = new HashMap<>();
// message.put("type", "text");
// Map<String, Object> properties = new HashMap<>();
// properties.put("message", message);
// Map<String, Object> mapping = new HashMap<>();
// mapping.put("properties", properties);
// createIndexRequest.mapping(mapping);


// 指定映射3
// XContentBuilder builder = XContentFactory.jsonBuilder();
// builder.startObject();
// {
// builder.startObject("properties");
// {
// builder.startObject("message");
// {
// builder.field("type", "text");
// }
// builder.endObject();
// }
// builder.endObject();
// }
// builder.endObject();
// createIndexRequest.mapping(builder);


// 额外参数
//设置超时时间
createIndexRequest.setTimeout(TimeValue.timeValueMinutes(2));
//设置主节点超时时间
createIndexRequest.setMasterTimeout(TimeValue.timeValueMinutes(1));
//在创建索引API返回响应之前等待的活动分片副本的数量,以int形式表示
createIndexRequest.waitForActiveShards(ActiveShardCount.from(2));
createIndexRequest.waitForActiveShards(ActiveShardCount.ALL);

// 执行操作
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);

boolean acknowledged = createIndexResponse.isAcknowledged();

boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();

String index = createIndexResponse.index();

System.out.println("ankonwledged:" + acknowledged);

System.out.println("shardsAcknowledged:" + shardsAcknowledged);
}


/**
* 异步创建
* @throws Exception
*/
@Test
public void testCreateIndexIndexAsync() throws Exception {

CreateIndexRequest createIndexRequest = new CreateIndexRequest("wyb_index");

createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));

//指定映射1
createIndexRequest.mapping(" {\n" +
" \t\"properties\": {\n" +
" \"name\":{\n" +
" \"type\":\"keyword\"\n" +
" },\n" +
" \"description\": {\n" +
" \"type\": \"text\"\n" +
" },\n" +
" \"price\":{\n" +
" \"type\":\"long\"\n" +
" },\n" +
" \"pic\":{\n" +
" \"type\":\"text\",\n" +
" \"index\":false\n" +
" }\n" +
" \t}\n" +
"}", XContentType.JSON);

ActionListener<CreateIndexResponse> actionListener = new ActionListener<>() {
@Override
public void onResponse(CreateIndexResponse createIndexResponse) {
System.out.println("索引创建成功");
System.out.println(createIndexResponse.toString());
}

@Override
public void onFailure(Exception e) {
System.out.println("索引创建失败");
e.printStackTrace();
}
};


client.indices().createAsync(createIndexRequest,RequestOptions.DEFAULT,actionListener);

Thread.sleep(2000);
}

/**
* 删除索引
* @throws Exception
*/
@Test
public void testDeleteIndex() throws Exception {

DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("wyb_index");

AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);

System.out.println("isAcknowledged:"+ delete.isAcknowledged());
}

/**
* 异步删除索引
* @throws Exception
*/
@Test
public void testDeleteIndexAsync() throws Exception {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("wyb_index");

ActionListener<AcknowledgedResponse> actionListener = new ActionListener<>() {
@Override
public void onResponse(AcknowledgedResponse deleteIndexResponse) {
System.out.println("!!!!!!!!删除索引成功");
System.out.println(deleteIndexResponse.toString());
}

@Override
public void onFailure(Exception e) {
System.out.println("!!!!!!!!删除索引失败");
e.printStackTrace();
}
};
}
/**
* 检查是否存在该索引
* @throws IOException
*/
@Test
public void testExistIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("wyb_index");
request.local(false);//从主节点返回本地信息或检索状态
request.humanReadable(true);//以适合人类的格式返回结果
request.includeDefaults(false);//是否返回每个索引的所有默认设置

boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}

/**
* 关闭索引
* @throws Exception
*/
@Test
public void testCloseIndex() throws Exception{
CloseIndexRequest closeIndexRequest = new CloseIndexRequest("wyb_index");

AcknowledgedResponse close = client.indices().close(closeIndexRequest, RequestOptions.DEFAULT);

System.out.println("isAcknowledged:" + close.isAcknowledged());
}

/**
* 打开索引
* @throws Exception
*/
@Test
public void testOpenIndex() throws Exception {

OpenIndexRequest openIndexRequest = new OpenIndexRequest("wyb_index");

OpenIndexResponse open = client.indices().open(openIndexRequest, RequestOptions.DEFAULT);

System.out.println("isAcknowledged:" + open.isAcknowledged());
}

}

search搜索

搜索语法

无条件搜索

1
GET /book/_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
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "book",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
......
}
}
]
}
}

took:耗费了几毫秒

timed_out:是否超时

_shards:到几个分片搜索,成功几个,跳过几个,失败几个

hits.total:查询结果的数量

hits.max_score:document对于一个search的相关度的匹配分数,越相关,就越匹配,分数也高

hits.hits:匹配搜索的document的所有详细数据

传参式

1
GET /book/_search?q=name:java&sort=price:desc
1
GET /book/_search?timeout=10ms

请求时间参数,也可以在配置文件中设置,search.default_search_timeout:100ms,默认不超时

多索引搜索

multi-index搜索

/_search:所有索引下的所有数据都搜索出来

/index1/_search:指定一个index,搜索其下所有的数据

/index1,index2/_search:同时搜索两个index下的数据

/index*/_search:按照通配符去匹配多个索引

分页搜索

1
GET /book/_search?from=6&size=3

deep paging

根据相关度评分倒排序

deep paging性能

  • 消耗网络带宽

  • 消耗内存

  • 消耗cpu

Query String语法

1
2
3
GET /book/_search?q=name:java
GET /book/_search?q=+name:java
GET /book/_search?q=-name:java

+:查询某一字段内容

-:不查询某一字段内容

_all metadata的原理

1
GET /book/_search?q=java

es中_all元数据。建立索引的时候,插入一条docunment,es会将所有的field值经行全量分词,把这些分词,放到_all field中。在搜索的时候,没有指定field,就在_all搜索

Query DSL

es特有的搜索语言,可在请求体中携带搜索条件

语法练习

  • 查询name中含有java的并且分页从第一数据显示10条数据并且按照价格降序排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /book/_search
{
"query": {
"match": {
"name": "java"
}
},
"sort": [
{
"price": "desc"
}
],
"from": 0,
"size": 10
}

多个搜索条件

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
GET /website/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "elasticsearch"
}
}
],
"should": [
{
"match": {
"content": "elasticsearch"
}
}
],
"must_not": [
{
"match": {
"author_id": 111
}
}
]
}
}
}

must:必须包含

should:可不可以都行

must_not:必须不包含

全文检索

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
PUT /book/
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"name":{
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"description":{
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"studymodel":{
"type": "keyword"
},
"price":{
"type": "double"
},
"timestamp": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"pic":{
"type":"text",
"index":false
}
}
}
}

建立索引时, description字段 term进行倒排索引

编号
java 2,3
程序员 3

搜索时,直接找description中含有java的文档 2,3,程序员在3中,3中出现两次,所以得分高,排在前面,2号文档含有一个java,排在后面

DSL 语法总结

match_all

  • 查询全部
1
2
3
4
5
6
7
8
GET /book/_search
{
"query": {
"match_all": {

}
}
}

match

  • 指定字段查询
1
2
3
4
5
6
7
8
GET  /book/_search
{
"query" : {
"match" : {
"description" : "java程序员"
}
}
}

multi_match

  • 查询多个字段
1
2
3
4
5
6
7
8
9
GET /book/_search
{
"query": {
"multi_match": {
"query": "java程序员",
"fields": ["name","description"]
}
}
}

range

  • 范围查询
1
2
3
4
5
6
7
8
9
10
11
GET /book/_search
{
"query": {
"range": {
"price": {
"gte": 80,
"lte": 90
}
}
}
}

gte:大于等于

lte:小于等于

term query

  • 字段为keyword时,存储和搜索都不分词
1
2
3
4
5
6
7
8
GET /book/_search
{
"query": {
"term": {
"description": "java程序员"
}
}
}

terms query

1
2
3
4
5
6
7
8
9
10
11
12
GET /book/_search
{
"query": {
"terms": {
"tags": [
"search",
"full_text",
"nosql"
]
}
}
}

exist query

  • 查询有某些字段值的文档
1
2
3
4
5
6
7
8
GET /book/_search
{
"query": {
"exists": {
"field": "description"
}
}
}

Fuzzy query

  • 返回包含与搜索词类似的词的文档
1
2
3
4
5
6
7
8
9
10
GET /book/_search
{
"query": {
"fuzzy": {
"description": {
"value": "jave"
}
}
}
}

Ids

1
2
3
4
5
6
7
8
GET /book/_search
{
"query": {
"ids": {
"values": ["1","4","22"]
}
}
}

prefix 前缀查询

  • 查询特定字段前缀匹配的内容
1
2
3
4
5
6
7
8
9
10
GET /book/_search
{
"query": {
"prefix": {
"description": {
"value": "spring"
}
}
}
}

regexp query 正则查询

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /book/_search
{
"query": {
"regexp": {
"description": {
"value": "j.*a",
"flags": "ALL",
"max_determinized_states": 10000,
"rewrite": "constant_score"
}
}
}
}

Filter

仅仅只是按照搜索条件过滤出需要的数据而已,不计算任何相关度分数,对相关度没有任何影响

  • 查询description中有java程序员,并且价格大于80小于90的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
GET /book/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"description": "java程序员"
}
}
],
"filter": {
"range": {
"price": {
"gte": 80,
"lte": 90
}
}
}
}
}
}

Filter VS Query性能

Filter不需要计算相关度分数,不需要按照相关度分数进行排序,同时还有内置的自动cache最常使用filter的数据

Query,相反,要计算相关度分数,按照分数进行排序,而且无法cache结果

定位语法错误

1
2
3
4
5
6
7
8
GET /book/_validate/query?explain
{
"query": {
"match": {
"description": "java程序员"
}
}
}

Text字段排序

将一个text field建立两次索引,一个分词,用来进行搜索;一个不分词,用来进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT /website 
{
"mappings": {
"properties": {
"title": {
"type": "text",
"fielddata": true
},
"content": {
"type": "text"
},
"post_date": {
"type": "date"
},
"author_id": {
"type": "long"
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PUT /website 
{
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"content": {
"type": "text"
},
"post_date": {
"type": "date"
},
"author_id": {
"type": "long"
}
}
}
}
  • test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /website/_search
{
"query": {
"match_all": {

}
},
"sort": [
{
"title.keyword": {
"order": "desc"
}
}
]
}

Scroll分批查询

滚动搜索技术,一批一批查询

原理

scoll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,是不会让用户看到的

每次发送scroll请求,我们还需要指定一个scoll参数,指定一个时间窗口

1
2
3
4
5
6
7
GET /book/_search?scroll=1m
{
"query": {
"match_all": {}
},
"size": 3
}

获得的结果会有一个scoll_id,下一次再发送scoll请求的时候,必须带上这个scoll_id

Scorll VS 分页

分页给用户看的 deep paging

scroll是用户系统内部操作,如下载批量数据,数据转移。零停机改变索引映射

Java实现搜索

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
package com.dream.xiaobo;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.util.Map;

/**
* @author xiaobo
* @date 2022/11/24 - 14:01
*/
@SpringBootTest(classes = ElasticsearchSpringBootApplication.class)
@RunWith(SpringRunner.class)
public class TestSearch {

@Autowired
private RestHighLevelClient client;

/**
* 查询全部
*/
@Test
public void testSearchAll() throws IOException {

// 构建请求
SearchRequest searchRequest = new SearchRequest("book");

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

searchSourceBuilder.query(QueryBuilders.matchAllQuery());

// 获取某些字段
searchSourceBuilder.fetchSource(new String[]{"name"},new String[] {});

searchRequest.source(searchSourceBuilder);

// 执行搜索
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

// 拿到结果
SearchHits hits = search.getHits();

// 获取数据
SearchHit[] hitsHits = hits.getHits();

for (SearchHit hitsHit : hitsHits) {
String id = hitsHit.getId();
float score = hitsHit.getScore();
System.out.println("id:" + id);
System.out.println("score:" + score);
Map<String, Object> sourceAsMap = hitsHit.getSourceAsMap();

String name = (String) sourceAsMap.get("name");

String description = (String) sourceAsMap.get("description");

Double price = (Double) sourceAsMap.get("price");

System.out.println("name:" + name);
System.out.println("description:" + description);
System.out.println("price:" + price);

System.out.println("---------------------------");

}
}

/**
* 分页搜索
*/
@Test
public void testSearchAllPage() throws IOException {

// 构建请求
SearchRequest searchRequest = new SearchRequest("book");

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

searchSourceBuilder.query(QueryBuilders.matchAllQuery());

int page = 1;

int size = 3;

int from = (page - 1) * size;

searchSourceBuilder.from(from);
searchSourceBuilder.size(size);

searchSourceBuilder.fetchSource(new String[]{"name"},new String[]{});

searchRequest.source(searchSourceBuilder);

// 执行搜索
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

// 拿到结果
SearchHits hits = search.getHits();

// 获取数据
SearchHit[] hitsHits = hits.getHits();

for (SearchHit hitsHit : hitsHits) {
String id = hitsHit.getId();
float score = hitsHit.getScore();
System.out.println("id:" + id);
System.out.println("score:" + score);
Map<String, Object> sourceAsMap = hitsHit.getSourceAsMap();

String name = (String) sourceAsMap.get("name");

String description = (String) sourceAsMap.get("description");

Double price = (Double) sourceAsMap.get("price");

System.out.println("name:" + name);
System.out.println("description:" + description);
System.out.println("price:" + price);

System.out.println("---------------------------");

}

}

/**
* ids查询
* @throws IOException
*/
@Test
public void testIdsSearch() throws IOException {

SearchRequest searchRequest = new SearchRequest("book");

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

searchSourceBuilder.query(QueryBuilders.idsQuery().addIds("1", "2", "4"));


searchRequest.source(searchSourceBuilder);

SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

SearchHits hits = search.getHits();
SearchHit[] hitss = hits.getHits();

for (SearchHit documentFields : hitss) {

String id = documentFields.getId();
float score = documentFields.getScore();
System.out.println("id:" + id);
System.out.println("score:" + score);
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();

String name = (String) sourceAsMap.get("name");

String description = (String) sourceAsMap.get("description");

Double price = (Double) sourceAsMap.get("price");

System.out.println("name:" + name);
System.out.println("description:" + description);
System.out.println("price:" + price);

System.out.println("---------------------------");
}
}

/**
* prefix查询
* @throws IOException
*/
@Test
public void testSearchPrefix() throws IOException {

SearchRequest searchRequest = new SearchRequest("book");

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

searchSourceBuilder.query(QueryBuilders.prefixQuery("description","spring"));

searchRequest.source(searchSourceBuilder);

SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

SearchHits hits = search.getHits();
SearchHit[] hitss = hits.getHits();

for (SearchHit documentFields : hitss) {

String id = documentFields.getId();
float score = documentFields.getScore();
System.out.println("id:" + id);
System.out.println("score:" + score);
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();

String name = (String) sourceAsMap.get("name");

String description = (String) sourceAsMap.get("description");

Double price = (Double) sourceAsMap.get("price");

System.out.println("name:" + name);
System.out.println("description:" + description);
System.out.println("price:" + price);

System.out.println("---------------------------");
}
}
/**
* el表达式查询
* @throws IOException
*/
@Test
public void testSearchRegexp() throws IOException {
SearchRequest searchRequest = new SearchRequest("book");

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

searchSourceBuilder.query(QueryBuilders.regexpQuery("description","j.*a"));

searchRequest.source(searchSourceBuilder);

SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);

SearchHits hits = search.getHits();
SearchHit[] hitss = hits.getHits();

for (SearchHit documentFields : hitss) {

String id = documentFields.getId();
float score = documentFields.getScore();
System.out.println("id:" + id);
System.out.println("score:" + score);
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();

String name = (String) sourceAsMap.get("name");

String description = (String) sourceAsMap.get("description");

Double price = (Double) sourceAsMap.get("price");

System.out.println("name:" + name);
System.out.println("description:" + description);
System.out.println("price:" + price);

System.out.println("---------------------------");
}
}

}

正确的开始 微小的长进 然后持续 嘿 我是小博 带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:elk 三

文章作者:小博

发布时间:2022年12月30日 - 15:56

最后更新:2022年12月30日 - 15:57

原始链接:https://codexiaobo.github.io/posts/1670905143/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。