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_" } } } } }
|
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> </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;
@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"));
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);
createIndexRequest.setTimeout(TimeValue.timeValueMinutes(2)); createIndexRequest.setMasterTimeout(TimeValue.timeValueMinutes(1)); 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); }
@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"));
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); }
@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()); }
@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(); } }; }
@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); }
@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()); }
@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 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性能
Query String语法
1 2 3
| GET /book/_search?q=name:java GET /book/_search?q=+name:java GET /book/_search?q=-name:java
|
+
:查询某一字段内容
-
:不查询某一字段内容
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进行倒排索引
搜索时,直接找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
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" } } } }
|
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" } } ] }
|
滚动搜索技术,一批一批查询
原理
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;
@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("---------------------------");
}
}
@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("---------------------------"); } }
@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("---------------------------"); } }
@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("---------------------------"); } }
}
|
正确的开始 微小的长进 然后持续 嘿 我是小博 带你一起看我目之所及的世界……