Elasticsearch学习

1.搜索引擎技术排名:

1.Elasticsearch:开源的分布式搜索引擎

2.Splunk:商业项目

3.Solr:Apache的开源搜索引擎

2.认识和安装

Elasticsearch结合kibana、Logstash、Beats,是一整套技术栈,被叫做ELK。被广泛应用在日志数据分析、实时监控等领域。

3.倒排索引:

传统数据库(MySQL)采用正向索引,例如给下表(tb_goods)中的id创建索引:

Elasticsearch采用倒排索引:

文档(document):每条数据就是一个文档,对文档中的内容分词,得到的词语就是词条

词条(term):文档按语义分成的词语

正向索引:基于文档id创建索引。根据id查询快,但是查询词条时必须先找到文档,而后判断是否包含词条

倒排索引:对文档内容分词,对词条创建索引,并记录词条所在文档的id.查询时先根据词条查询到文档id,而后根据文档id查询文档

4.IK分词器

IK分词器:中文分词器往往根据语义分析,比较复杂,这就需要用到中文分词器,例如IK分词器,IK分词器是林良益在2006年开源发布的,其采用的正向迭代最细颗粒度切分算法一直沿用至今。

POST /_analyze[[ZW(1]](#[ZW(1])

{

"analyzer":"standard",

"text":"xxxxx"

}

POST:请求方式

/_analyze:请求路径

请求参数,json风格:

Analyzer:分词器类型,这里是默认的standard分词器。

Text:要分词的内容。

分词器的作用:1.创建倒排索引时,对文档分词;2.用户搜索时,对输入的内容分词

IK分词器有几种模式?1.ik_smart:智能切分,粗粒度;2.ik_max_word:最细切分,细粒度IK分词器

扩展分词器词库中的词条:1.利用config目录的ikAnalyzer.cfg.xml文件添加拓展词典 2.在词典中添加拓展词条。

5.索引与映射

索引(index):相同类型的文档的集合

映射(mapping):索引中文档的字段约束信息,类似表的结构约束

Mapping是对索引库中文档的约束,常见的mapping属性包括:

1.type:字段数据类型,常见的简单类型有:

字符串:text(可分词的文本)、keyword(精确值)

数值:long、integer、short、byte、double、float

布尔:boolean

日期:date

对象:object

2.index:是否创建索引,默认为true

3.analyzer:使用哪种分词器

4.properties:该字段的子字段

索引是为了搜索或者排序

6.索引库操作:

Elasticsearch提供的所有API都是Restful的接口,遵循Restful的基本规范:

查看索引库语法:

GET /索引库名

删除索引库的语法:

DELETE /索引库名

索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法如下:

修改已有字段不可以,添加新的字段可以

索引库操作有哪些?

创建索引库:PUT/索引库名

查询索引库:GET/索引库名

删除索引库:DELETE/索引库名

添加字段:PUT/索引库名/_mapping

7.文档CRUD:

新增文档的请求格式如下:

POST/索引库名/_doc/文档id

{

"字段1":"值1",

"字段2":"值2",

"字段3":{

"子属性1":"值3",

"子属性2":"值4"

}"

}

修改文档:方式一:全量修改,会删除旧文档,添加新文档

PUT /索引名/_doc/文档id

{

"字段1":"值1",

"字段2":"值2",

}

方式二:增量修改,修改指定字段值

POST /索引库名/_update/文档id

{

"doc":{

"字段名":"新的值",

}

}

8.客户端初始化es:

1.引入es的RestHighLevelClient依赖:

2.因为SpringBoot默认的ES版本为7.17.0,所以我们需要覆盖默认的ES版本:如需要指定版本的ES:

3.初始化RestHighLevelClient:

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(

HttpHost.create("http://192.168.xx.xx:xxx")

));

9.用javaAPI方式进行创建、删除、查询索引库、对文档CRUD

(1)创建索引库javaAPI:

@Test

Void testCreateHotelIndex() throws IOException{

//1.创建Request对象

CreateIndexRequest request = new CreateIndexRequest("items");

//2.请求参数,MAPPING_TEMPLATE是静态常量字符串,内容是JSON格式请求体

Request.source(MAPPING_TEMPLATE,XcontentType.JSON);

//3.发起请求

Client.indices().create(request,RequestOptions.DEFAULT);

}

(2)删除索引库:

@Test

void testDeleteHotelIndex() throws IOException {

//1.创建Request对象

DeleteIndexRequest request = new DeleteIndexRequest("indexName");

//2.发起请求

Client.indices().delete(request,RequestOptions.DEFAULT);

}

(3)查询索引库信息:

@Test

Void testExistsHotelIndex() throws IOException {

//1.创建Request对象

GetIndexRequest request = new GetIndexRequest("indexName");

//2.发起请求

Client.indices().get(request,RequestOptions.DEFAULT);

}

(4)新增文档的javaAPI如下:

@Test

Void testIndexDocument() throws IOException{

//1.创建request对象

IndexRequest request = new IndexRequest("indexName").id("1");

//2.准备JSON文档

Request.source("{\"name\":\"Jack\",\"age\":21}",XContentType.JSON);

//3.发送请求

Client.index(request,RequestOptions.DEFAULT);

}

(5)删除文档的javaAPI如下:

@Test

Void testDeleteDocumentById() throws IOException {

DeleteRequest request = new DeleteRequest("indexName","1");

//删除文档

client.delete(request,RequestOption.DEFAULT);

}

(6)查询文档包含查询和解析响应结果两部分

@Test

Void testGetDocumentByid( ) throws IOException {

//创建request对象

GetRequest request = new GetRequest("indexName","1");

//发送请求,得到结果

GetResponse response = client.get(request,RequestOptions.DEFAULT);

//解析结果

String json = response.getSourceAsString( );

System.out.println(json);

}

文档操作两种方式:

方式一:全量更新。再次写入id一样的文档,就会删除旧文档,添加新文档。与新增的javaAPI一致

方法二:局部更新。只更新指定部分字段

@Test

Void testUpdateDocumentByid() throws IOException {

UpdateRequest request = new UpdateRequest("indexName","1");

Request.doc(xxxx);

Client.update(request,RequestOptions.DEFAULT);

}

(7)文档操作的基本步骤:

1.初始化RestHighLevelClient

2.创建XXXRequest.XXX是index、get、update、delete

3.准备参数(index和Update时需要)

4.发送请求。调用RestHighLevelClient#.xxx()方法,xxx是index、get、update、delete

5.解析结果(get时需要)

(8)批处理:

构建请求会用到一个名为BulkRequest来封装普通的CRUD请求

批处理API示例:

@Test

Void testBulk() throws IOException{

//1.创建Bulk请求

BulkRequest request = new BulkRequest();

//2.添加要批量提交的请求:以添加两个新增文档的请求为例:

Request.add(new IndexRequest("indexName")).id("101").source("json source",XcontentType.JSON));

Request.add(new IndexRequest("indexName").id("102").source("json source",XcontentType.JSON));

//发起bulk请求

Client.bulk(request,RequestOptions.DEFAULT);

}

10.DSL查询可以分为两大类:

叶子查询:一般在特定的字段里查询特定值,属于简单查询,很少单独使用。

复合查询:以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。

在查询以后,还可以对查询的结果做处理,包括:

1.排序:按照1个或多个字段值做排序

2.分页:根据from和size做分页,类似MySQL

3.高亮:对搜索结果中的关键字添加特殊样式,使其更加醒目

4.聚合:对搜索结果做数据统计以形成报表

查询所有

GET /indexName/_search

{

"query":{

"match_all":{

}

}

}

ES单次查询最大数据不能超过10000个

全文检索查询:利用分词器对用户输入内容分词,然后去词条列表中匹配。例如:match_query、multi_match_query

精确查询:不对用户输入内容分词,直接精确匹配,一般是查找keyword、数值、日期、布尔等类型。例如:ids、range、term

地理查询:用于搜索地理位置,搜索方式很多。例如:geo_distance、geo_bounding_box

Match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索:

GET /indexName/_search

{

"query":{

"match":{

"FIELD":"TEXT"

}

}

}

Multi_match:与match查询类似,只不过允许同时查询多个字段

GET /indexName/_search

{

"query":{

"multi_match":{

"query":"TEXT",

"fields":["FIELD1","FIELD12"]

}

}

}

全文检索有得分,默认按照得分排名显示

精确查询:词条级别查询,不对用户输入的搜索条件再分词,作为一个词条,与搜索的字段内容精确值匹配。所以推荐查找keyword、数值、日期、boolean类型的字段

全文检索查询:Match和multi_match的区别:match根据一个字段查询,multi_match:根据多个字段查询,参与查询字段越多,查询性能越差

精确查询:term查询:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段 range查询:根据数值范围查询,可以是数值、日期的范围

11.复合查询

1.基于逻辑运算组合叶子查询,实现组合条件,bool;2.基于某种算法修改查询时的文档相关性算分,从而改变文档排名。Function_score、dis_max

布尔查询是一个或多个查询子句的组合。子查询的组合方式有:

Must:必须匹配每个子查询,类似"与"

Should:选择性匹配子查询,类似"或"

Must_not:必须不匹配,不参与算分,类似"非"

Filter:必须匹配,不参与算分

排序和分页

ES支持对搜索结果排序,默认是根据相关度算分(_score)来排序,也可以指定字段排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

GET /indexName/_search

{

"query"{

"match_all":{}

},

"sort"[

{

"FIELD":"desc"//排序字段和排序方式ASC、DESC

}

]

}

ES默认情况下只返回top10的数据。如果想要查询更多数据就需要修改分页参数,ES中通过修改from、size参数来控制要返回的分页结果:

From:从第几个文档开始

Size:总共查询几个文档

GET /items/_search

{

"query":{

"match_all":{}

},

"from":0,//分页开始的位置,默认为0、表示从第几条记录开始(默认为0,表示从第一条开始)

"size":10,期望获取的文档总数

"sort":[

{"price": "asc"}

]

}

12.深度分页问题:

ES的数据一般采用分片存储,将一个索引中的数据分成N份,存储到不同节点上。查询数据时需要汇总各个分片的数据。

查找第100页数据,每页查找10条:

GET /hotel/_search

{

"from": 990,

"size": 10,

}

对数据排序,并找出第990-1000名数据

深度分页问题:有两种方案:search after分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。Scroll:原理将排序数据形成快照,保存在内存。

Search after模式:

优点:没有查询上限,支持深度分页

缺点:只能向后逐页查询,不能随机翻页

场景:数据迁移,手机滚动查询

13.es的api操作:

(1)搜索完整语法:

GET /item/_search

{

"query":{

"match":{

"name":"小米"

}

},

"from":0//分页开始的位置

"size":20//期望获取的文档总数

"sort":[

{"price":"asc"},//普通排序

],

"highlight":{

"fields":{//高亮字段

"name":{

"pre_tags":"<em>",//高亮字段的前置标签

"post_tags":"</em>"//高亮字段的后置标签

}

}

}

}

对应的Java后端写法:

@Test

Void testMatchAll( ) throw IOException {

//准备Request

SearchRequest request = new SearchRequest("indexName");

//组织DSL参数

request.source( ).query(QueryBuliders.matchAllQuery());

//发送请求,得到响应结果

SearchResponse response = client.search(request, RequestOptions.DEFAULT);

}

全文检索的查询条件构造API如下:

Java后端语句QueryBuilders.matchQuery("name","脱脂牛奶")

和下面查询语句一样

GET /items/_search

{

"query":{

"match:{

"name":"脱脂牛奶"

}"

}

}

Java后端语句QueryBuilders.multiMatchQuery("脱脂牛奶","name","category");

和下面查询语句一样

GET /items/_search

{

"query":{

"multi_match":{

"query":"脱脂牛奶",

"field":["category","name"]

}

}

}

(2)精确查询

Java后端语句QueryBuilders.termQuery("category","牛奶");//词条查询

和下面查询语句一样

GET /items/_search

{

"query":{

"item":{

"category":"牛奶"

}

}

}

Java后端语句QueryBuilders.rangeQuery("price").gte(100).lte(150)//范围查询gte、lte大于,小于

和下面查询语句一样

GET /items/_search

{

"query":{

"range":{

"price":{"gte":100,"lte":150}

}

}

}

Java后端语句布尔查询的查询条件

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();//创建布尔查询

boolQuery.must(QueryBuilders.termQuery("brand","华为"));//添加must条件

boolQuery.filter(QueryBuilders.rangeQuery("price").lte(2500));//添加filter条件

上述布尔查询的条件语句和下面一样

GET /items/_search

{

"query":{

"bool":{

"must":[

{

"term": {"brand":"华为"}

}

],

"filter":[

{

"range":{

"price":{"lte":2500}

}

}

]

}

}

}

Java后端语句主要使用的是querybuilders来构建查询条件来实现对es内部操作一样的语句

与query类似,排序和分页参数都是基于request.source()来设置:

request.source().query(QueryBuilders.matchAllQuery());//查询

request.source().from(0).size(5)//分页

request.source().sort("price",SortOrder.ASC);

上述查询与分页语句和下面可视化窗口语句一样

GET /indexName/_search

{

"query":{

"match_all":{ }

},

"from":0,

"size":5,

"sort":[

{

"FIELD":"desc"

}

]

}

Java后端语句request.source().highlight(

SearchSourceBuilder.highlight()

.field("name")

.preTags("<em>")

.postTags("</em>")

)

上述高亮显示语句与可视化窗口中的语句效果一致:

GET /items/_search

{

"query":{

"match":{

"name":"脱脂牛奶"

}

},

"highlight":{

"fields":{

"name"{

"pre_tags":"<em>",

"post_tags":"</em>"

}

}

}

}

14.数据聚合

数据聚合:可以实现对文档数据的统计、分析、运算。聚合常见的有三类:

桶(Bucket)聚合:用来对文档做分组

TermAggregation:按照文档字段值分组

Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组

度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等

Avg:求平均值

Max:求最大值

Min:求最小值

Stats:同时求max、min、avg、sum等

管道(pipeline)聚合:其他聚合的结果为基础做聚合

参与聚合的字段必须是Keyword、数值、日期、布尔的类型的字段。

15.DSL聚合

统计所有商品中共有哪些商品分类,其实就是以分类(category)字段对数据分组。Category值一样的放在同一组,属于bucket聚合中的term聚合。

GET /items/_search

{

"query":{"match_all":{}},

"size":0, //设置size

"args":{

"cateAgg":{

"terms":{

"field":"category",

"size":20

}

}

}

}

}

默认情况下,Bucket聚合是对索引库的所有文档做聚合,可以限定聚合范围,加入query条件即可

对每个bukect内的数据进一步做数据计算和统计

相关推荐
TDengine (老段)2 小时前
TDengine GROUP BY 与 PARTITION BY 使用及区别深度分析
大数据·开发语言·数据库·物联网·时序数据库·tdengine·涛思数据
下雨打伞干嘛2 小时前
前端学习官网文档
前端·学习
代码方舟2 小时前
Java Spring Boot 实战:构建天远高并发个人消费能力评估系统
java·大数据·spring boot·python
k***92162 小时前
Linux网络编程】应用层协议HTTP(实现一个简单的http服务)
java·开发语言·学习
zhixingheyi_tian2 小时前
Hadoop 编译
java·大数据·hadoop
慎独4132 小时前
锚定智能化浪潮,其目科技以“硬核科技+数据闭环”重塑脑力教育新范式
大数据·人工智能
数据猿11 小时前
【金猿CIO展】上海虹迪物流科技有限公司董事长兼CIO张鹏飞:聚焦数字化核心——物流供应链的的智慧演进之路
大数据·科技
Java后端的Ai之路11 小时前
【神经网络基础】-神经网络学习全过程(大白话版)
人工智能·深度学习·神经网络·学习