ELK高级搜索(三)

文章目录

    • 11.索引Index入门
      • 11.1 索引管理
      • 11.2 定制分词器
      • 11.3 type底层结构
      • 11.4 定制dynamic mapping
      • 11.5 零停机重建索引
    • 12.中文分词器 IK分词器
      • 12.1 Ik分词器安装使用
      • 12.2 ik配置文件
      • 12.3 使用mysql热更新
    • 13.java api 实现索引管理
    • 14.search搜索入门
      • 14.1 搜索语法入门
      • 14.2 multi-index 多索引搜索
      • 14.3 分页搜索
      • 14.4 query string基础语法
      • 14.5 query DSL入门
      • 14.6 full-text search 全文检索
      • 14.7 DSL 语法练习
      • 14.8 Filter
      • 14.9 定位错误语法
      • 14.10 定制排序规则
      • 14.11 Text字段排序问题
      • 14.12 Scroll分批查询
    • 15.java api实现搜索

11.索引Index入门

11.1 索引管理

直接put数据 PUT index/_doc/1,es会自动生成索引,并建立动态映射dynamic mapping。

在生产上,需要自己手动建立索引和映射,为了更好地管理索引。就像数据库的建表语句一样。

11.1.1 创建索引

创建索引的语法

PUT /index
{"settings": { ... any settings ... },"mappings": {"properties" : {"field1" : { "type" : "text" }}},"aliases": {"default_index": {}} 
}

举例:

PUT /my_index
{"settings": {"number_of_shards": 1,"number_of_replicas": 1},"mappings": {"properties": {"field1":{"type": "text"},"field2":{"type": "text"}}},"aliases": {"default_index": {}} 
}

索引别名

插入数据

POST /my_index/_doc/1
{"field1":"java","field2":"js"
}

查询数据 都可以查到

GET /my_index/_doc/1

GET /default_index/_doc/1

11.1.2 查询索引

GET /my_index/_mapping

GET /my_index/_setting

11.1.3 修改索引

修改副本数

PUT /my_index/_settings
{"index" : {"number_of_replicas" : 2}
}

11.1.4 删除索引

DELETE /my_index

DELETE /index_one,index_two

DELETE /index_*

DELETE /_all

为了安全起见,防止恶意删除索引,删除时必须指定索引名:

elasticsearch.yml

action.destructive_requires_name: true

11.2 定制分词器

11.2.1 默认的分词器

standard

分词三个组件,character filter,tokenizer,token filter

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

standard token filter:什么都不做

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

stop token filer(默认被禁用):移除停用词,比如a the it等等

11.2.2 修改分词器的设置

启用english停用词token filter

PUT /my_index
{"settings": {"analysis": {"analyzer": {"es_std": {"type": "standard","stopwords": "_english_"}}}}
}

测试分词

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"
}

11.2.3 定制化自己的分词器

PUT /my_index
{"settings": {"analysis": {"char_filter": {"&_to_and": {"type": "mapping","mappings": ["&=> and"]}},"filter": {"my_stopwords": {"type": "stop","stopwords": ["the", "a"]}},"analyzer": {"my_analyzer": {"type": "custom","char_filter": ["html_strip", "&_to_and"],"tokenizer": "standard","filter": ["lowercase", "my_stopwords"]}}}}
}

测试

GET /my_index/_analyze
{"analyzer": "my_analyzer","text": "tom&jerry are a friend in the house, <a>, HAHA!!"
}

设置字段使用自定义分词器

PUT /my_index/_mapping/
{"properties": {"content": {"type": "text","analyzer": "my_analyzer"}}
}

11.3 type底层结构

11.3.1 type是什么

type,是一个index中用来区分类似的数据的,类似的数据,但是可能有不同的fields,而且有不同的属性来控制索引建立、分词器。
field的value,在底层的lucene中建立索引的时候,全部是opaque bytes类型,不区分类型的。
lucene是没有type的概念的,在document中,实际上将type作为一个document的field来存储,即_type,es通过_type来进行type的过滤和筛选。

11.3.2 es中不同type存储机制

一个index中的多个type,实际上是放在一起存储的,因此一个index下,不能有多个type重名,而类型或者其他设置不同的,因为那样是无法处理的

{"goods": {"mappings": {"electronic_goods": {"properties": {"name": {"type": "string",},"price": {"type": "double"},"service_period": {"type": "string"}			}},"fresh_goods": {"properties": {"name": {"type": "string",},"price": {"type": "double"},"eat_period": {"type": "string"}}}}}
}
PUT /goods/electronic_goods/1
{"name": "小米空调","price": 1999.0,"service_period": "one year"
}
PUT /goods/fresh_goods/1
{"name": "澳洲龙虾","price": 199.0,"eat_period": "one week"
}

es文档在底层的存储

{"goods": {"mappings": {"_type": {"type": "text","index": "false"},"name": {"type": "text"}"price": {"type": "double"}"service_period": {"type": "text"},"eat_period": {"type": "text"}}}
}

底层数据存储格式

{"_type": "electronic_goods","name": "小米空调","price": 1999.0,"service_period": "one year","eat_period": ""
}
{"_type": "fresh_goods","name": "澳洲龙虾","price": 199.0,"service_period": "","eat_period": "one week"
}

11.3.3 type弃用

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

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

es9中,将会彻底删除type。

11.4 定制dynamic mapping

11.4.1 定制dynamic策略

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

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

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

创建mapping

PUT /my_index
{"mappings": {"dynamic": "strict","properties": {"title": {"type": "text"},"address": {"type": "object","dynamic": "true"}}}
}

插入数据

PUT /my_index/_doc/1
{"title": "my article","content": "this is my article","address": {"province": "guangdong","city": "guangzhou"}
}

报错

{"error": {"root_cause": [{"type": "strict_dynamic_mapping_exception","reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed"}],"type": "strict_dynamic_mapping_exception","reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed"},"status": 400
}

11.4.2 自定义dynamic mapping策略

es会根据传入的值,推断类型。

在这里插入图片描述

date_detection 日期探测

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

PUT /my_index
{"mappings": {"date_detection": false,"properties": {"title": {"type": "text"},"address": {"type": "object","dynamic": "true"}}}
}

测试

PUT /my_index/_doc/1
{"title": "my article","content": "this is my article","address": {"province": "guangdong","city": "guangzhou"},"post_date":"2019-09-10"
}

查看映射

GET /my_index/_mapping

自定义日期格式

PUT my_index
{"mappings": {"dynamic_date_formats": ["MM/dd/yyyy"]}
}

插入数据

PUT my_index/_doc/1
{"create_date": "09/25/2019"
}

numeric_detection 数字探测

虽然json支持本机浮点和整数数据类型,但某些应用程序或语言有时可能将数字呈现为字符串。通常正确的解决方案是显式地映射这些字段,但是可以启用数字检测(默认情况下禁用)来自动完成这些操作。

PUT my_index
{"mappings": {"numeric_detection": true}
}
PUT my_index/_doc/1
{"my_float":   "1.0", "my_integer": "1" 
}

11.4.3 定制自己的dynamic mapping template

PUT /my_index
{"mappings": {"dynamic_templates": [{ "en": {"match":              "*_en", "match_mapping_type": "string","mapping": {"type":           "text","analyzer":       "english"}}                  }]}
}

插入数据

PUT /my_index/_doc/1
{"title": "this is my first article"
}PUT /my_index/_doc/2
{"title_en": "this is my first article"
}

搜索

GET my_index/_search?q=first
GET my_index/_search?q=is

title没有匹配到任何的dynamic模板,默认就是standard分词器,不会过滤停用词,is会进入倒排索引,用is来搜索是可以搜索到的

title_en匹配到了dynamic模板,就是english分词器,会过滤停用词,is这种停用词就会被过滤掉,用is来搜索就搜索不到了

模板写法

PUT my_index
{"mappings": {"dynamic_templates": [{"integers": {"match_mapping_type": "long","mapping": {"type": "integer"}}},{"strings": {"match_mapping_type": "string","mapping": {"type": "text","fields": {"raw": {"type":  "keyword","ignore_above": 256}}}}}]}
}

模板参数

"match":   "long_*",
"unmatch": "*_text",
"match_mapping_type": "string",
"path_match":   "name.*",
"path_unmatch": "*.middle",
"match_pattern": "regex",
"match": "^profit_\d+$"

场景

1 结构化搜索

默认情况下,elasticsearch将字符串字段映射为带有子关键字字段的文本字段。但是,如果只对结构化内容进行索引,而对全文搜索不感兴趣,则可以仅将“字段”映射为“关键字”。请注意,这意味着为了搜索这些字段,必须搜索索引所用的完全相同的值。

	{"strings_as_keywords": {"match_mapping_type": "string","mapping": {"type": "keyword"}}}

2 仅搜索

与前面的示例相反,如果您只关心字符串字段的全文搜索,并且不打算对字符串字段运行聚合、排序或精确搜索,您可以告诉弹性搜索将其仅映射为文本字段(这是5之前的默认行为)

	 {"strings_as_text": {"match_mapping_type": "string","mapping": {"type": "text"}}}

3 norms 不关心评分

norms是指标时间的评分因素。如果您不关心评分,例如,如果您从不按评分对文档进行排序,则可以在索引中禁用这些评分因子的存储并节省一些空间。

{"strings_as_keywords": {"match_mapping_type": "string","mapping": {"type": "text","norms": false,"fields": {"keyword": {"type": "keyword","ignore_above": 256}}}}}

11.5 零停机重建索引

11.5.1 零停机重建索引

场景:

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

批量查询的时候,建议采用scroll api,并且采用多线程并发的方式来reindex数据,每次scoll就查询指定日期的一段数据,交给一个线程即可。

(1)一开始,依靠dynamic mapping,插入数据,但是不小心有些数据是2019-09-10这种日期格式的,所以title这种field被自动映射为了date类型,实际上它应该是string类型的。

PUT /my_index/_doc/1
{"title": "2019-09-10"
}PUT /my_index/_doc/2
{"title": "2019-09-11"
}

(2)当后期向索引中加入string类型的title值的时候,就会报错。

PUT /my_index/_doc/3
{"title": "my first article"
}

报错

{"error": {"root_cause": [{"type": "mapper_parsing_exception","reason": "failed to parse [title]"}],"type": "mapper_parsing_exception","reason": "failed to parse [title]","caused_by": {"type": "illegal_argument_exception","reason": "Invalid format: \"my first article\""}},"status": 400
}

(3)如果此时想修改title的类型,是不可能的。

PUT /my_index/_mapping
{"properties": {"title": {"type": "text"}}
}

报错

{"error": {"root_cause": [{"type": "illegal_argument_exception","reason": "mapper [title] of different type, current_type [date], merged_type [text]"}],"type": "illegal_argument_exception","reason": "mapper [title] of different type, current_type [date], merged_type [text]"},"status": 400
}

(4)此时,唯一的办法,就是进行reindex,也就是说,重新建立一个索引,将旧索引的数据查询出来,再导入新索引。

(5)如果说旧索引的名字,是old_index,新索引的名字是new_index,终端java应用,已经在使用old_index在操作了,难道还要去停止java应用,修改使用的index为new_index,才重新启动java应用吗?这个过程中,就会导致java应用停机,可用性降低。

(6)所以说,给java应用一个别名,这个别名是指向旧索引的,java应用先用着,java应用先用prod_index alias来操作,此时实际指向的是旧的my_index。

PUT /my_index/_alias/prod_index

(7)新建一个index,调整其title的类型为string。

PUT /my_index_new
{"mappings": {"properties": {"title": {"type": "text"}}}
}

(8)使用scroll api将数据批量查询出来。

GET /my_index/_search?scroll=1m
{"query": {"match_all": {}},    "size":  1
}

返回

{"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAADpAFjRvbnNUWVZaVGpHdklqOV9zcFd6MncAAAAAAAA6QRY0b25zVFlWWlRqR3ZJajlfc3BXejJ3AAAAAAAAOkIWNG9uc1RZVlpUakd2SWo5X3NwV3oydwAAAAAAADpDFjRvbnNUWVZaVGpHdklqOV9zcFd6MncAAAAAAAA6RBY0b25zVFlWWlRqR3ZJajlfc3BXejJ3","took": 1,"timed_out": false,"_shards": {"total": 5,"successful": 5,"failed": 0},"hits": {"total": 3,"max_score": null,"hits": [{"_index": "my_index","_type": "my_type","_id": "1","_score": null,"_source": {"title": "2019-01-02"},"sort": [0]}]}
}

(9)采用bulk api将scoll查出来的一批数据,批量写入新索引。

POST /_bulk
{ "index":  { "_index": "my_index_new", "_id": "1" }}
{ "title":    "2019-09-10" }

(10)反复循环8~9,查询一批又一批的数据出来,采取bulk api将每一批数据批量写入新索引。

(11)将prod_index alias切换到my_index_new上去,java应用会直接通过index别名使用新的索引中的数据,java应用程序不需要停机,零提交,高可用。

POST /_aliases
{"actions": [{ "remove": { "index": "my_index", "alias": "prod_index" }},{ "add":    { "index": "my_index_new", "alias": "prod_index" }}]
}

(12)直接通过prod_index别名来查询,是否ok。

GET /prod_index/_search

11.5.2 生产实践:基于alias对client透明切换index

PUT /my_index_v1/_alias/my_index

client对my_index进行操作

reindex操作,完成之后,切换v1到v2

POST /_aliases
{"actions": [{ "remove": { "index": "my_index_v1", "alias": "my_index" }},{ "add":    { "index": "my_index_v2", "alias": "my_index" }}]
}

12.中文分词器 IK分词器

12.1 Ik分词器安装使用

12.1.1 中文分词器

standard 分词器,仅适用于英文。

GET /_analyze
{"analyzer": "standard","text": "中华人民共和国人民大会堂"
}

想要的效果是什么:中华人民共和国,人民大会堂

IK分词器就是目前最流行的es中文分词器

12.1.2 安装

官网:https://github.com/medcl/elasticsearch-analysis-ik

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

根据es版本下载相应版本包。

解压到 es/plugins/ik中。

重启es

12.1.3 ik分词器基础知识

ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民大会堂,人民大会,大会堂”,会穷尽各种可能的组合;

ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国,人民大会堂”。

12.1.4 ik分词器的使用

存储时,使用ik_max_word,搜索时,使用ik_smart

PUT /my_index 
{"mappings": {"properties": {"text": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"}}}
}

搜索

GET /my_index/_search?q=中华人民共和国人民大会堂

12.2 ik配置文件

12.2.1 ik配置文件

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

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

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

  • preposition.dic: 介词

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

  • suffix.dic:放了一些后缀

  • surname.dic:中国的姓氏

  • stopword.dic:英文停用词

ik原生最重要的两个配置文件:

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

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

停用词,stopword

a the and at but 停用词,会在分词的时候,直接被干掉,不会建立在倒排索引中

12.2.2 自定义词库

(1)自己建立词库:每年都会涌现一些特殊的流行词,网红,蓝瘦香菇,喊麦,鬼畜,一般不会在ik的原生词典里

  • 自己补充自己的最新的词语,到ik的词库里面

  • IKAnalyzer.cfg.xml:ext_dict,创建mydict.dic

  • 补充自己的词语,然后需要重启es,才能生效

(2)自己建立停用词库:比如了,的,啥,么,我们可能并不想去建立索引,让人家搜索

  • custom/ext_stopword.dic,已经有了常用的中文停用词,可以补充自己的停用词,然后重启es

12.3 使用mysql热更新

12.3.1 热更新

每次都是在es的扩展词典中,手动添加新词语,很坑

(1)每次添加完,都要重启es才能生效,非常麻烦

(2)es是分布式的,可能有数百个节点,你不能每次都一个一个节点上面去修改

es不停机,直接我们在外部某个地方添加新的词语,es中立即热加载到这些新词语

热更新的方案

(1)基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新

(2)修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库

用第二种方案,第一种,ik git社区官方都不建议采用,觉得不太稳定

12.3.2 步骤

1、下载源码

https://github.com/medcl/elasticsearch-analysis-ik/releases

ik分词器,是个标准的java maven工程,直接导入eclipse就可以看到源码

2、修改源

  • org.wltea.analyzer.dic.Dictionary类,160行Dictionary单例类的初始化方法,在这里需要创建一个我们自定义的线程,并且启动它

  • org.wltea.analyzer.dic.HotDictReloadThread类:就是死循环,不断调用Dictionary.getSingleton().reLoadMainDict(),去重新加载词典

  • Dictionary类,399行:this.loadMySQLExtDict(); 加载mymsql字典

  • Dictionary类,609行:this.loadMySQLStopwordDict();加载mysql停用词

  • config下jdbc-reload.properties。mysql配置文件

3、mvn package打包代码

target\releases\elasticsearch-analysis-ik-7.3.0.zip

4、解压缩ik压缩包

将mysql驱动jar,放入ik的目录下

5、修改jdbc相关配置

6、重启es

观察日志,日志中就会显示我们打印的那些东西,比如加载了什么配置,加载了什么词语,什么停用词

7、在mysql中添加词库与停用词

8、分词实验,验证热更新生效

GET /_analyze
{"analyzer": "ik_smart","text": "传智播客"
}

13.java api 实现索引管理

package com.itheima.es;import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.Alias;
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.IndicesClient;
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 Administrator- @version 1.0**/@SpringBootTest@RunWith(SpringRunner.class)public class TestIndex {@AutowiredRestHighLevelClient client;//    @Autowired
//    RestClient restClient;​```
//创建索引
@Test
public void testCreateIndex() throws IOException {//创建索引对象CreateIndexRequest createIndexRequest = new CreateIndexRequest("itheima_book");//设置参数createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));//指定映射1createIndexRequest.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.alias(new Alias("itheima_index_new"));// 额外参数//设置超时时间createIndexRequest.setTimeout(TimeValue.timeValueMinutes(2));//设置主节点超时时间createIndexRequest.setMasterTimeout(TimeValue.timeValueMinutes(1));//在创建索引API返回响应之前等待的活动分片副本的数量,以int形式表示createIndexRequest.waitForActiveShards(ActiveShardCount.from(2));createIndexRequest.waitForActiveShards(ActiveShardCount.DEFAULT);//操作索引的客户端IndicesClient indices = client.indices();//执行创建索引库CreateIndexResponse createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);//得到响应(全部)boolean acknowledged = createIndexResponse.isAcknowledged();//得到响应 指示是否在超时前为索引中的每个分片启动了所需数量的碎片副本boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!" + acknowledged);System.out.println(shardsAcknowledged);}//异步新增索引
@Test
public void testCreateIndexAsync() throws IOException {//创建索引对象CreateIndexRequest createIndexRequest = new CreateIndexRequest("itheima_book2");//设置参数createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));//指定映射1createIndexRequest.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> listener =new ActionListener<CreateIndexResponse>() {@Overridepublic void onResponse(CreateIndexResponse createIndexResponse) {System.out.println("!!!!!!!!创建索引成功");System.out.println(createIndexResponse.toString());}@Overridepublic void onFailure(Exception e) {System.out.println("!!!!!!!!创建索引失败");e.printStackTrace();}};//操作索引的客户端IndicesClient indices = client.indices();//执行创建索引库indices.createAsync(createIndexRequest, RequestOptions.DEFAULT, listener);try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}
​```​```
}
​```​```
//删除索引库
@Test
public void testDeleteIndex() throws IOException {//删除索引对象DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("itheima_book2");//操作索引的客户端IndicesClient indices = client.indices();//执行删除索引AcknowledgedResponse delete = indices.delete(deleteIndexRequest, RequestOptions.DEFAULT);//得到响应boolean acknowledged = delete.isAcknowledged();System.out.println(acknowledged);}//异步删除索引库
@Test
public void testDeleteIndexAsync() throws IOException {//删除索引对象DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("itheima_book2");//操作索引的客户端IndicesClient indices = client.indices();//监听方法ActionListener<AcknowledgedResponse> listener =new ActionListener<AcknowledgedResponse>() {@Overridepublic void onResponse(AcknowledgedResponse deleteIndexResponse) {System.out.println("!!!!!!!!删除索引成功");System.out.println(deleteIndexResponse.toString());}@Overridepublic void onFailure(Exception e) {System.out.println("!!!!!!!!删除索引失败");e.printStackTrace();}};//执行删除索引indices.deleteAsync(deleteIndexRequest, RequestOptions.DEFAULT, listener);try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}// Indices Exists API
@Test
public void testExistIndex() throws IOException {GetIndexRequest request = new GetIndexRequest("itheima_book");request.local(false);//从主节点返回本地信息或检索状态request.humanReadable(true);//以适合人类的格式返回结果request.includeDefaults(false);//是否返回每个索引的所有默认设置boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println(exists);
}
​```​```
// Indices Open API
@Test
public void testOpenIndex() throws IOException {OpenIndexRequest request = new OpenIndexRequest("itheima_book");OpenIndexResponse openIndexResponse = client.indices().open(request, RequestOptions.DEFAULT);boolean acknowledged = openIndexResponse.isAcknowledged();System.out.println("!!!!!!!!!"+acknowledged);
}// Indices Close API
@Test
public void testCloseIndex() throws IOException {CloseIndexRequest request = new CloseIndexRequest("index");AcknowledgedResponse closeIndexResponse = client.indices().close(request, RequestOptions.DEFAULT);boolean acknowledged = closeIndexResponse.isAcknowledged();System.out.println("!!!!!!!!!"+acknowledged);}
}

14.search搜索入门

14.1 搜索语法入门

14.1.1 query string search

无条件搜索所有

GET /book/_search
{"took" : 969,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 3,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "book","_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : {"name" : "Bootstrap开发","description" : "Bootstrap是由Twitter推出的一个前台页面开发css框架,是一个非常流行的开发框架,此框架集成了多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长css页面开发的程序人员)轻松的实现一个css,不受浏览器限制的精美界面css效果。","studymodel" : "201002","price" : 38.6,"timestamp" : "2019-08-25 19:11:35","pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg","tags" : ["bootstrap","dev"]}},{"_index" : "book","_type" : "_doc","_id" : "2","_score" : 1.0,"_source" : {"name" : "java编程思想","description" : "java语言是世界第一编程语言,在软件开发领域使用人数最多。","studymodel" : "201001","price" : 68.6,"timestamp" : "2019-08-25 19:11:35","pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg","tags" : ["java","dev"]}},{"_index" : "book","_type" : "_doc","_id" : "3","_score" : 1.0,"_source" : {"name" : "spring开发基础","description" : "spring 在java领域非常流行,java程序员都在用。","studymodel" : "201001","price" : 88.6,"timestamp" : "2019-08-24 19:11:35","pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg","tags" : ["spring","java"]}}]}
}

解释

  • took:耗费了几毫秒

  • timed_out:是否超时,这里是没有

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

  • hits.total:查询结果的数量,3个document

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

  • hits.hits:包含了匹配搜索的document的所有详细数据

14.1.2 传参

与http请求传参类似

GET /book/_search?q=name:java&sort=price:desc

类比sql: select * from book where name like ’ %java%’ order by price desc

{"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "book","_type" : "_doc","_id" : "2","_score" : null,"_source" : {"name" : "java编程思想","description" : "java语言是世界第一编程语言,在软件开发领域使用人数最多。","studymodel" : "201001","price" : 68.6,"timestamp" : "2019-08-25 19:11:35","pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg","tags" : ["java","dev"]},"sort" : [68.6]}]}
}

14.1.3 图解timeout

GET /book/_search?timeout=10ms

全局设置:配置文件中设置 search.default_search_timeout:100ms。默认不超时。

在这里插入图片描述

14.2 multi-index 多索引搜索

14.2.1 multi-index搜索模式

如何一次性搜索多个index和多个type下的数据

/_search:所有索引下的所有数据都搜索出来
/index1/_search:指定一个index,搜索其下所有的数据
/index1,index2/_search:同时搜索两个index下的数据
/index*/_search:按照通配符去匹配多个索引

应用场景:生产环境log索引可以按照日期分开。

log_to_es_20190910

log_to_es_20190911

log_to_es_20180910

14.2.2 图解简单的搜索原理

搜索原理初步图解

在这里插入图片描述

14.3 分页搜索

14.3.1 分页搜索的语法

sql: select * from book limit 1,5

size,from

GET /book/_search?size=10

GET /book/_search?size=10&from=0

GET /book/_search?size=10&from=20

GET /book_search?from=0&size=3

14.3.2 deep paging

什么是deep paging

根据相关度评分倒排序,所以分页过深,协调节点会将大量数据聚合分析。

在这里插入图片描述

deep paging 性能问题

1 消耗网络带宽,因为所搜过深的话,各 shard 要把数据传递给 coordinate node,这个过程是有大量数据传递的,消耗网络。

2 消耗内存,各 shard 要把数据传送给 coordinate node,这个传递回来的数据,是被 coordinate node 保存在内存中的,这样会大量消耗内存。

3 消耗cup,coordinate node 要把传回来的数据进行排序,这个排序过程很消耗cpu。

所以:鉴于deep paging的性能问题,所有应尽量减少使用。

14.4 query string基础语法

14.4.1 query string基础语法

GET /book/_search?q=name:java

GET /book/_search?q=+name:java

GET /book/_search?q=-name:java

一个是掌握q=field:search content的语法,还有一个是掌握+和-的含义

14.4.2 _all metadata的原理和作用

GET /book/_search?q=java

直接可以搜索所有的field,任意一个field包含指定的关键字就可以搜索出来。我们在进行中搜索的时候,难道是对document中的每一个field都进行一次搜索吗?不是的。

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

举例

{name:jackemail:123@qq.comaddress:beijing
}

_all : jack,123@qq.com,beijing

14.5 query DSL入门

14.5.1 DSL

query string 后边的参数原来越多,搜索条件越来越复杂,不能满足需求。

GET /book/_search?q=name:java&size=10&from=0&sort=price:desc

DSL:Domain Specified Language,特定领域的语言

es特有的搜索语言,可在请求体中携带搜索条件,功能强大。

查询全部 GET /book/_search

GET /book/_search
{"query": { "match_all": {} }
}

排序 GET /book/_search?sort=price:desc

GET /book/_search 
{"query" : {"match" : {"name" : " java"}},"sort": [{ "price": "desc" }]
}

分页查询 GET /book/_search?size=10&from=0

GET  /book/_search 
{"query": { "match_all": {} },"from": 0,"size": 1
}

指定返回字段 GET /book/ _search? _source=name,studymodel

GET /book/_search 
{"query": { "match_all": {} },"_source": ["name", "studymodel"]
}

通过组合以上各种类型查询,实现复杂查询。

14.5.2 Query DSL语法

{QUERY_NAME: {ARGUMENT: VALUE,ARGUMENT: VALUE,...}
}
{QUERY_NAME: {FIELD_NAME: {ARGUMENT: VALUE,ARGUMENT: VALUE,...}}
}
GET /test_index/_search 
{"query": {"match": {"test_field": "test"}}
}

14.5.3 组合多个搜索条件

搜索需求:title必须包含elasticsearch,content可以包含elasticsearch也可以不包含,author_id必须不为111

sql where and or !=

初始数据:

POST /website/_doc/1
{"title": "my hadoop article","content": "hadoop is very bad","author_id": 111
}POST /website/_doc/2
{"title": "my elasticsearch  article","content": "es is very bad","author_id": 112
}
POST /website/_doc/3
{"title": "my elasticsearch article","content": "es is very goods","author_id": 111
}

搜索:

GET /website/_doc/_search
{"query": {"bool": {"must": [{"match": {"title": "elasticsearch"}}],"should": [{"match": {"content": "elasticsearch"}}],"must_not": [{"match": {"author_id": 111}}]}}
}

返回:

{"took" : 488,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.47000363,"hits" : [{"_index" : "website","_type" : "_doc","_id" : "2","_score" : 0.47000363,"_source" : {"title" : "my elasticsearch  article","content" : "es is very bad","author_id" : 112}}]}
}

更复杂的搜索需求:

select * from test_index where name=‘tom’ or (hired =true and (personality =‘good’ and rude != true ))

GET /test_index/_search
{"query": {"bool": {"must": { "match":{ "name": "tom" }},"should": [{ "match":{ "hired": true }},{ "bool": {"must":{ "match": { "personality": "good" }},"must_not": { "match": { "rude": true }}}}],"minimum_should_match": 1}}
}

14.6 full-text search 全文检索

14.6.1 全文检索

重新创建book索引

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}}}
}

插入数据

PUT /book/_doc/1
{
"name": "Bootstrap开发",
"description": "Bootstrap是由Twitter推出的一个前台页面开发css框架,是一个非常流行的开发框架,此框架集成了多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长css页面开发的程序人员)轻松的实现一个css,不受浏览器限制的精美界面css效果。",
"studymodel": "201002",
"price":38.6,
"timestamp":"2019-08-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "bootstrap", "dev"]
}PUT /book/_doc/2
{
"name": "java编程思想",
"description": "java语言是世界第一编程语言,在软件开发领域使用人数最多。",
"studymodel": "201001",
"price":68.6,
"timestamp":"2019-08-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "java", "dev"]
}PUT /book/_doc/3
{
"name": "spring开发基础",
"description": "spring 在java领域非常流行,java程序员都在用。",
"studymodel": "201001",
"price":88.6,
"timestamp":"2019-08-24 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "spring", "java"]
}

搜索

GET  /book/_search 
{"query" : {"match" : {"description" : "java程序员"}}
}

14.6.2 _score初探

{"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 2.137549,"hits" : [{"_index" : "book","_type" : "_doc","_id" : "3","_score" : 2.137549,"_source" : {"name" : "spring开发基础","description" : "spring 在java领域非常流行,java程序员都在用。","studymodel" : "201001","price" : 88.6,"timestamp" : "2019-08-24 19:11:35","pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg","tags" : ["spring","java"]}},{"_index" : "book","_type" : "_doc","_id" : "2","_score" : 0.57961315,"_source" : {"name" : "java编程思想","description" : "java语言是世界第一编程语言,在软件开发领域使用人数最多。","studymodel" : "201001","price" : 68.6,"timestamp" : "2019-08-25 19:11:35","pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg","tags" : ["java","dev"]}}]}
}

结果分析

1、建立索引时, description字段 term倒排索引

  • java 2,3
  • 程序员 3

2、搜索时直接找description中含有java的文档 2,3,并且3号文档含有两个java字段一个程序员,所以得分高排在前面,2号文档含有一个java排在后面。

14.7 DSL 语法练习

14.7.1 match_all

GET /book/_search
{"query": {"match_all": {}}
}

14.7.2 match

GET /book/_search
{"query": { "match": { "description": "java程序员"}}
}

14.7.3 multi_match

GET /book/_search
{"query": {"multi_match": {"query": "java程序员","fields": ["name", "description"]}}
}

14.7.4 range query 范围查询

GET /book/_search
{"query": {"range": {"price": {"gte": 80,"lte": 90}}}
}

14.7.5 term query

字段为keyword时,存储和搜索都不分词

GET /book/_search
{"query": {"term": {"description": "java程序员"}}
}

14.7.6 terms query

GET /book/_search
{"query": { "terms": { "tag": [ "search", "full_text", "nosql" ] }}
}

14.7.7 exist query 查询有某些字段值的文档

GET /_search
{"query": {"exists": {"field": "join_date"}}
}

14.7.8 Fuzzy query

返回包含与搜索词类似的词的文档,该词由Levenshtein编辑距离度量。

包括以下几种情况:

  • 更改角色(box→fox)

  • 删除字符(aple→apple)

  • 插入字符(sick→sic)

  • 调换两个相邻字符(ACT→CAT)

GET /book/_search
{"query": {"fuzzy": {"description": {"value": "jave"}}}
}

14.7.9 IDs

GET /book/_search
{"query": {"ids" : {"values" : ["1", "4", "100"]}}
}

14.7.10 prefix 前缀查询

GET /book/_search
{"query": {"prefix": {"description": {"value": "spring"}}}
}

14.7.11 regexp query 正则查询

GET /book/_search
{"query": {"regexp": {"description": {"value": "j.*a","flags" : "ALL","max_determinized_states": 10000,"rewrite": "constant_score"}}}
}

14.8 Filter

14.8.1 filter与query示例

需求:用户查询description中有"java程序员",并且价格大于80小于90的数据。

GET /book/_search
{"query": {"bool": {"must": [{"match": {"description": "java程序员"}},{"range": {"price": {"gte": 80,"lte": 90}}}]}}
}

使用filter:

GET /book/_search
{"query": {"bool": {"must": [{"match": {"description": "java程序员"}}],"filter": {"range": {"price": {"gte": 80,"lte": 90}}}}}
}

14.8.2 filter与query对比

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

query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序。

应用场景:

  • 一般来说,如果你是在进行搜索,需要将最匹配搜索条件的数据先返回,那么用query
  • 如果你只是要根据一些条件筛选出一部分数据,不关注其排序,那么用filter

14.8.3 filter与query性能

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

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

14.9 定位错误语法

验证错误语句:

GET /book/_validate/query?explain
{"query": {"mach": {"description": "java程序员"}}
}

返回:

{"valid" : false,"error" : "org.elasticsearch.common.ParsingException: no [query] registered for [mach]"
}

正确

GET /book/_validate/query?explain
{"query": {"match": {"description": "java程序员"}}
}

返回

{"_shards" : {"total" : 1,"successful" : 1,"failed" : 0},"valid" : true,"explanations" : [{"index" : "book","valid" : true,"explanation" : "description:java description:程序员"}]
}

一般用在那种特别复杂庞大的搜索下,比如一下写了上百行的搜索,这个时候可以先用validate api去验证一下,搜索是否合法。

合法以后,explain就像mysql的执行计划,可以看到搜索的目标等信息。

14.10 定制排序规则

14.10.1 默认排序规则

默认情况下,是按照_score降序排序的

然而,某些情况下,可能没有有用的_score,比如说filter

GET book/_search
{"query": {"bool": {"must": [{"match": {"description": "java程序员"}}]}}
}

当然,也可以是constant_score

14.10.2 定制排序规则

相当于sql中order by ?sort=sprice:desc

GET /book/_search 
{"query": {"constant_score": {"filter" : {"term" : {"studymodel" : "201001"}}}},"sort": [{"price": {"order": "asc"}}]
}

14.11 Text字段排序问题

如果对一个text field进行排序,结果往往不准确,因为分词后是多个单词,再排序就不是我们想要的结果了。

通常解决方案是:

方案一:fielddate:true

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

PUT /website 
{"mappings": {"properties": {"title": {"type": "text","fields": {"keyword": {"type": "keyword"}        }      },"content": {"type": "text"},"post_date": {"type": "date"},"author_id": {"type": "long"}}}
}

插入数据

PUT /website/_doc/1
{"title": "first article","content": "this is my second article","post_date": "2019-01-01","author_id": 110
}PUT /website/_doc/2
{"title": "second article","content": "this is my second article","post_date": "2019-01-01","author_id": 110
}PUT /website/_doc/3
{"title": "third article","content": "this is my third article","post_date": "2019-01-02","author_id": 110
}

搜索

GET /website/_search
{"query": {"match_all": {}},"sort": [{"title.keyword": {"order": "desc"}}]
}

14.12 Scroll分批查询

场景:下载某一个索引中1亿条数据,到文件或是数据库。不能一下全查出来,系统内存溢出。所以使用scoll滚动搜索技术,一批一批查询。

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

每次发送scroll请求,我们还需要指定一个scoll参数,指定一个时间窗口,每次搜索请求只要在这个时间窗口内能完成就可以了。

搜索

GET /book/_search?scroll=1m
{"query": {"match_all": {}},"size": 3
}

返回

{"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAMOkWTURBNDUtcjZTVUdKMFp5cXloVElOQQ==","took" : 3,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 3,"relation" : "eq"},"max_score" : 1.0,"hits" : []}
}

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

GET /_search/scroll
{"scroll": "1m", "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAMOkWTURBNDUtcjZTVUdKMFp5cXloVElOQQ=="
}

与分页区别:

分页给用户看的 deep paging

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

15.java api实现搜索

package com.itheima.es;import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
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;/*** creste by itheima.itcast*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestSearch {@AutowiredRestHighLevelClient client;//搜索全部记录@Testpublic void testSearchAll() throws IOException {
//        GET book/_search
//        {
//            "query": {
//                "match_all": {}
//             }
//        }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.matchAllQuery());//获取某些字段searchSourceBuilder.fetchSource(new String[]{"name"}, new String[]{});searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.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("==========================");}}//搜索分页@Testpublic void testSearchPage() throws IOException {
//    GET book/_search
//    {
//        "query": {
//          "match_all": {}
//       },
//        "from": 0,
//        "size": 2
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.matchAllQuery());//第几页int page=1;//每页几个int size=2;//下标计算int from=(page-1)*size;searchSourceBuilder.from(from);searchSourceBuilder.size(size);searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}//ids搜索@Testpublic void testSearchIds() throws IOException {
//    GET /book/_search
//    {
//        "query": {
//           "ids" : {
//             "values" : ["1", "4", "100"]
//          }
//     }
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.idsQuery().addIds("1","4","100"));searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}//match搜索@Testpublic void testSearchMatch() throws IOException {
//
//    GET /book/_search
//    {
//        "query": {
//           "match": {
//            "description": "java程序员"
//        }
//      }
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.matchQuery("description", "java程序员"));searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}//term 搜索@Testpublic void testSearchTerm() throws IOException {
//
//    GET /book/_search
//    {
//        "query": {
//           "term": {
//            "description": "java程序员"
//        }
//      }
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.termQuery("description", "java程序员"));searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}//multi_match搜索@Testpublic void testSearchMultiMatch() throws IOException {
//    GET /book/_search
//    {
//        "query": {
//          "multi_match": {
//            "query": "java程序员",
//            "fields": ["name", "description"]
//        }
//      }
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(QueryBuilders.multiMatchQuery("java程序员","name","description"));searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}
//    GET /book/_search
//    {
//        "query": {
//        "bool": {
//            "must": [
//            {
//                "multi_match": {
//                "query": "java程序员",
//                        "fields": ["name","description"]
//            }
//            }
//      ],
//            "should": [
//            {
//                "match": {
//                "studymodel": "201001"
//            }
//            }
//      ]
//        }
//    }
//    }//bool搜索@Testpublic void testSearchBool() throws IOException {
//    GET /book/_search
//    {
//        "query": {
//          "bool": {
//            "must": [
//            {
//                "multi_match": {
//                  "query": "java程序员",
//                  "fields": ["name","description"]
//            }
//            }
//      ],
//            "should": [
//            {
//                "match": {
//                "studymodel": "201001"
//            }
//            }
//      ]
//        }
//    }
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//构建multiMatch请求MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("java程序员", "name", "description");//构建match请求MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("studymodel", "201001");BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();boolQueryBuilder.must(multiMatchQueryBuilder);boolQueryBuilder.should(matchQueryBuilder);searchSourceBuilder.query(boolQueryBuilder);searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}//    GET /book/_search
//    {
//        "query": {
//          "bool": {
//            "must": [
//            {
//                "multi_match": {
//                "query": "java程序员",
//                        "fields": ["name","description"]
//            }
//            }
//      ],
//            "should": [
//            {
//                "match": {
//                "studymodel": "201001"
//            }
//            }
//      ],
//            "filter": {
//                "range": {
//                    "price": {
//                        "gte": 50,
//                                "lte": 90
//                    }
//                }
//
//            }
//        }
//    }
//    }//filter搜索@Testpublic void testSearchFilter() throws IOException {
//    GET /book/_search
//    {
//        "query": {
//          "bool": {
//            "must": [
//            {
//                "multi_match": {
//                "query": "java程序员",
//                        "fields": ["name","description"]
//            }
//            }
//      ],
//            "should": [
//            {
//                "match": {
//                "studymodel": "201001"
//            }
//            }
//          ],
//            "filter": {
//                "range": {
//                    "price": {
//                        "gte": 50,
//                         "lte": 90
//                    }
//                }
//
//            }
//        }
//    }
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//构建multiMatch请求MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("java程序员", "name", "description");//构建match请求MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("studymodel", "201001");BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();boolQueryBuilder.must(multiMatchQueryBuilder);boolQueryBuilder.should(matchQueryBuilder);boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(50).lte(90));searchSourceBuilder.query(boolQueryBuilder);searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}//sort搜索@Testpublic void testSearchSort() throws IOException {
//    GET /book/_search
//    {
//        "query": {
//        "bool": {
//            "must": [
//            {
//                "multi_match": {
//                "query": "java程序员",
//                        "fields": ["name","description"]
//            }
//            }
//      ],
//            "should": [
//            {
//                "match": {
//                "studymodel": "201001"
//            }
//            }
//      ],
//            "filter": {
//                "range": {
//                    "price": {
//                        "gte": 50,
//                                "lte": 90
//                    }
//                }
//
//            }
//        }
//    },
//        "sort": [
//        {
//            "price": {
//            "order": "asc"
//        }
//        }
//  ]
//    }//1构建搜索请求SearchRequest searchRequest = new SearchRequest("book");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//构建multiMatch请求MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("java程序员", "name", "description");//构建match请求MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("studymodel", "201001");BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();boolQueryBuilder.must(multiMatchQueryBuilder);boolQueryBuilder.should(matchQueryBuilder);boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(50).lte(90));searchSourceBuilder.query(boolQueryBuilder);//按照价格升序searchSourceBuilder.sort("price", SortOrder.ASC);searchRequest.source(searchSourceBuilder);//2执行搜索SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//3获取结果SearchHits hits = searchResponse.getHits();//数据数据SearchHit[] searchHits = hits.getHits();System.out.println("--------------------------");for (SearchHit hit : searchHits) {String id = hit.getId();float score = hit.getScore();Map<String, Object> sourceAsMap = hit.getSourceAsMap();String name = (String) sourceAsMap.get("name");String description = (String) sourceAsMap.get("description");Double price = (Double) sourceAsMap.get("price");System.out.println("id:" + id);System.out.println("name:" + name);System.out.println("description:" + description);System.out.println("price:" + price);System.out.println("==========================");}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/121126.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka-- kafka集群环境搭建

kafka集群环境搭建 # 准备zookeeper环境 (zookeeper-3.4.6) # 下载kafka安装包 https://archive.apache.org/dist/kafka/2.1.0/kafka_2.12-2.1.0.tgz # 上传 : 172.16.144.133 cd /usr/local/softwaretar -zxvf /usr/local/software/kafka_2.12-2.1.0.tgz -C /usr/local…

Kubernetes_概念篇

Kubernetes_概念篇 一、架构二、概念1&#xff0c;Label&#xff08;对象标签&#xff09;2&#xff0c;Namespace3&#xff0c;Deployment4&#xff0c;Service 三、资源对象Master组件1&#xff0c;kube-apiserver2&#xff0c;kube-controller-manager3&#xff0c;kube-sch…

go语言基础语法

1、注释 package mainimport "fmt"/* *多行注释*/ func main() {//单行注释fmt.Println("hello world") }2、变量 2.1、变量定义 标准格式 var 变量名 变量类型 如 var age int Go语言的基本类型有&#xff1a; boolstringint、int8、int16、int32、…

什么是安全运营中心(SOC),应该了解什么

安全运营中心&#xff08;SOC&#xff09; 是一种企业监视和警报设施&#xff0c;可帮助组织检测安全威胁、监视安全事件和分析性能数据以改进公司运营。 什么是安全运营中心&#xff08;SOC&#xff09; 安全运营中心&#xff08;SOC&#xff09;是一个中央监视和监视中心&a…

Flowable7 设计器

1、flowable7 已经在主版本上移除了Flowable UI相关的包&#xff0c;包含bpm-json相关的所有包和流程设计器相关前端文件。 2、flowable7 版本目前只保留了xml运行相关的包&#xff0c;ui modeler已经移除 3、目前官方给的回复是只能在 flowable 云产品上使用设计器&#xff…

Servlet属性、监听者和会话

没有servlet能单独存在。在当前的现代Web应用中&#xff0c;许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息&#xff1f;如何隐藏信息&#xff1f;怎样让信息做到线程安全&#xff1f; 1 属性和监听者 1.1 初始化 容器初始化一个servlet时&#xff0c;会为…

国标GB28181视频平台EasyGBS国标视频云平台级联到EasyCVR,上级平台无法播放通道视频的问题解决方案

EasyGBS国标视频云平台是基于国标GB28181协议的视频能力兼服务平台&#xff0c;可实现的视频能力包括将设备通过国标GB28181协议接入、流媒体转码、处理及分发、直播录像、语音对讲、云存储、告警、平台级联等功能。其中&#xff0c;平台级联功能是指平台与平台之间可以通过国标…

真香:Alibaba开源GitHub星标100K微服务架构全彩进阶手册

前言&#xff1a; 微服务架构作为一种高效灵活的应用架构&#xff0c;正在成为企业级应用开发的主流选择。在众多的微服务架构指南中&#xff0c;阿里巴巴开源的GitHub微服务架构全彩进阶手册备受瞩目&#xff0c;其100star更是证明了其在开发者社区中的重要地位。 这本手册汇…

结构体的简单介绍(2)

目录 结构体的特殊声明 结构体的自引用 结构体的特殊声明 在声明结构的时候&#xff0c;可以不完全的声明。 比如&#xff1a; struct {int a;char b;float c; }x; 以上结构在声明的时候省略掉了结构体标签&#xff08;tag&#xff09;。 那么会有什么影响呢&#xff1f…

Unity 切换场景后场景变暗

问题 Unity版本&#xff1a;2019.4.34f1c1 主场景只有UI&#xff0c;没有灯光&#xff0c;天空盒&#xff1b;其他场景有灯光和天空盒所有场景不烘焙主场景作为启动场景运行&#xff0c;切换到其他场景&#xff0c;场景变暗某一个场景作为启动场景运行&#xff0c;光影效果正…

【zip密码】zip压缩包删除密码方法

Zip压缩包设置设置了密码&#xff0c;想要删除密码&#xff0c;除了将压缩包解压出来之后再将文件压缩为不带密码的压缩文件以外&#xff0c;还有一种删除密码的方法。设置方法如下&#xff1a; 右键点击zip文件&#xff0c;找到打开方式&#xff0c;以Windows资源管理器方式打…

数据结构:排序解析

文章目录 前言一、常见排序算法的实现1.插入排序1.直接插入排序2.希尔排序 2.交换排序1.冒泡排序2.快速排序1.hoare版2.挖坑版3.前后指针版4.改进版5.非递归版 3.选择排序1.直接选择排序2.堆排序 4.归并排序1.归并排序递归实现2.归并排序非递归实现 5.计数排序 二、排序算法复杂…

手写Mybatis:第17章-Plugin插件功能实现

文章目录 一、目标&#xff1a;Plugin插件二、设计&#xff1a;Plugin插件三、实现&#xff1a;Plugin插件3.1 工程结构3.2 Plugin插件代理模式类图3.3 自定义拦截注解3.3.1 方法签名3.3.2 拦截注解 3.4 拦截器接口定义3.4.1 调用信息3.4.2 拦截器接口 3.5 类代理包装操作3.5.1…

Vulnhub: Hogwarts: Bellatrix靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.228 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.228访问80端口 查看源码&#xff0c;提示ikilledsiriusblack.php和文件包含的参数名file 漏洞利用 ikilledsiriusblack.p…

seata升级1.1.0后遇到io.seata.common.exception.ShouldNeverHappenException

我们这一节主要讲的是seata升级后的主要修改&#xff0c;至于seata的基本部署可以参考我之前的随笔。 一开始我在升级SpringBoot版本之后&#xff0c;seata就突然启动不起来了&#xff0c;报了下面的错&#xff1a; Caused by: io.seata.common.exception.ShouldNeverHappenExc…

etcd读写请求的执行过程

etcd读请求如何执行 首先&#xff0c;etcdctl 会对命令中的参数进行解析。在解析完请求中的参数后&#xff0c;etcdctl 会创建一个 clientv3 库对象通过gRPC API来访问 etcd server。对应流程一。 然后通过负载均衡算法选择一个etcd server节点&#xff0c;然后调用 etcd ser…

互联网医院|医疗系统新模式改善看病效率

伴随着互联网时代的进步&#xff0c;医疗也在不断的发展&#xff0c;越来越多的医院和诊所开始使用医疗软件。医疗软件广泛的被使用着&#xff0c;软件几乎覆盖了我们的日常生活。在我们日常生活当中健康一直是需求专业渠道&#xff0c;医疗软件开发会把用户的数据打造出一个数…

2023年了,java后端还有未来吗?

前言 Java当下确实是比较的内卷&#xff0c;但关键在于个人&#xff0c;可以看看不同地方&#xff08;这里主要举例北上广深一线城市&#xff09;对于Java开发工程师这个职位的具体要求&#xff1a; 在以下北上广深这些一线大城市的面试招聘当中不难看出&#xff0c;凡是工资…

电视盒子什么品牌好?数码博主盘点目前性能最好的电视盒子

电视盒子是非常重要的&#xff0c;老人小孩基本每天都会看电视&#xff0c;而电视盒子作为电视盒子的最佳拍档销量十分火爆&#xff0c;我自己每个月都会测评几次电视盒子&#xff0c;今天给大家详细解读一下电视盒子什么品牌好&#xff0c;看看目前性能最好的电视盒子是哪些&a…

危险边缘:揭示 Python 编程中易被忽视的四个安全陷阱

今天我们将要谈论一个非常重要的话题&#xff1a;Python 编程中的安全问题。作为一门广受欢迎的编程语言&#xff0c;Python 已经成为了许多开发者、计算机专业学生以及打工人的必备技能。 原文链接食用更佳 危险边缘&#xff1a;揭示 Python 编程中易被忽视的四个安全问题 然…