Elasticsearch进阶笔记

  • 6、ES的核心概念
    • 1、概述
    • 2、Elasticsearch核心概念
      • 1、索引 index
      • 2、类型 type
      • 3、字段Field
      • 4、映射 mapping
      • 5、文档 document
      • 6、接近实时 NRT
      • 7、集群 cluster
      • 8、节点 node
      • 9、分片和复制 shards&replicas
  • 7、管理索引
    • 1、使用 Xput创建索引
      • 1、创建索引
      • 2、插入文档
      • 3、查询文档
      • 4、更新文档
      • 5、搜索文档
      • 6、删除文档
      • 7、删除索引
    • 2、查询条件查询
      • 1、使用match_all做查询
      • 2、通过关键字段进行查询
      • 3、bool的复合查询
      • 4、bool的复合查询中的should
      • 5、term匹配
      • 6、使用terms匹配多个值
      • 7、Range过滤
      • 8、exists和 missing过滤
      • 9、bool的多条件过滤
      • 10、查询与过滤条件合并
    • 3、定义字段类型mappings
      • 1、使用mappings来提前定义字段类型
      • 2、基本命令
      • 3、获取映射字段
    • 4、管理索引库分片数以及副本数settings
  • 8、分页解决方案
    • 1、导入数据
    • 2、size+from浅分页
    • 3、scroll深分页
  • 9、ES的中文分词器IK
    • 第一步:三台机器安装IK分词器
      • 将ik分词器的插件,解压到对应路径下
      • 三台机器都配置完成
      • 配置完成之后,需要重启服务。
    • 第二步、创建索引库并配置IK分词器
    • 第三步、查看分词效果
    • 第四步、插入测试数据
    • 第五步、配置热词更新
      • 1、node03配置Tomcat
      • 2、 三台机器修改配置文件
      • 3、三台机器重新启动es
  • 10、Elasticsearch的JavaAPI操作
    • 1:创建maven工程,并添加jar包坐标依赖
    • 2:添加索引文件操作
      • 1、创建Client
      • 2、自己拼装json创建索引保存到myindex1索引库下面的article当中去
      • 3、使用map创建索引
      • 4、XcontentBuilder实现创建索引
      • 5、将对象转换为json格式字符串进行创建索引
      • 6、批量创建索引
    • 3、查询索引
      • 1、初始化一批数据到索引库中准备查询
      • 2、通过数据id使用prepareGet来查询索引
      • 3、查询索引库当中的所有数据
      • 4、RangeQuery范围值查询
      • 5、termQuery词条查询
      • 6、fuzzyQuery模糊查询
      • 7、wildCardQuery通配符查询
      • 8、boolQuery 多条件组合查询
      • 9、分页与高亮查询
        • 1、分页查询
        • 2、高亮查询
        • 3、高亮显示的html分析
        • 4、高亮显示代码实现
    • 4、更新索引
    • 5、删除索引
      • 1、按照id进行删除
      • 2、按照查询条件来进行删除
      • 3、删除整个索引库
  • 11、es的高级javaAPI操作
  • 12、ES当中的地理位置搜索
    • 第一步:创建索引库并添加数据
    • 第二步:添加以下jar包坐标依赖
    • 第三步:使用javaAPI来实现基于地理位置的搜索
  • 13、elasticsearch 的sql插件使用
    • 第一种方式:通过rest风格实现数据的查询
      • 第一步:使用rest方式向索引库当中添加数据
      • 第二步:使用rest风格方式查询数据
    • 第二种方式:使用sql脚本的方式进入sql客户端进行查询
      • 第一步:node01进入sql脚本客户端
      • 第二步:执行sql语句
    • 第三种方式:通过jdbc连接的方式
      • 第一步:导入jar包
      • 第二步:开发java代码,实现查询

6、ES的核心概念

1、概述

Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。
Elasticsearch比传统关系型数据库如下:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields

2、Elasticsearch核心概念

1、索引 index

一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。

2、类型 type

在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。

3、字段Field

相当于是数据表的字段,对文档数据根据不同属性进行的分类标识

4、映射 mapping

mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其它就是处理es里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。

5、文档 document

一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。

6、接近实时 NRT

Elasticsearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒以内)

7、集群 cluster

一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群

8、节点 node

一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。

9、分片和复制 shards&replicas

一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因: 1)允许你水平分割/扩展你的内容容量。 2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,有两个主要原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。

7、管理索引

curl是利用URL语法在命令行方式下工作的开源文件传输工具,使用curl可以简单实现常见的get/post请求。简单的认为是可以在命令行下面访问url的一个工具。在centos的默认库里面是有curl工具的,如果没有请yum安装即可。
curl
-X 指定http的请求方法 有HEAD GET POST PUT DELETE
-d 指定要传输的数据
-H 指定http请求头信息

1、使用 Xput创建索引

1、创建索引

在我们的kibana的dev tools当中执行以下语句
curl -XPUT http://node01:9200/blog01/?pretty

2、插入文档

前面的命令使用 PUT 动词将一个文档添加到 /article(文档类型),并为该文档分配 ID 为1。URL 路径显示为index/doctype/ID(索引/文档类型/ID)。
curl -XPUT http://node01:9200/blog01/article/1?pretty -d ‘{“id”: “1”, “title”: “What is lucene”}’
问题:Content-Type header [application/x-www-form-urlencoded] is not supported
解决:
curl -XPUT http://node01:9200/blog01/article/1?pretty -d ‘{“id”: “1”, “title”: “What is lucene”}’ -H “Content-Type: application/json”
原因:
此原因时由于ES增加了安全机制, 进行严格的内容类型检查,严格检查内容类型也可以作为防止跨站点请求伪造攻击的一层保护。 官网解释
http.content_type.required

3、查询文档

curl -XGET http://node01:9200/blog01/article/1?pretty
问题:Content-Type header [application/x-www-form-urlencoded] is not supported
解决:
curl -XPUT http://node01:9200/blog01/article/1?pretty -d ‘{“id”: “1”, “title”: “What is lucene”}’ -H “Content-Type: application/json”
curl -XGET http://node01:9200/blog01/article/1?pretty -H “Content-Type: application/json”

4、更新文档

curl -XPUT http://node01:9200/blog01/article/1?pretty -d ‘{“id”: “1”, “title”: " What is elasticsearch"}’
问题:Content-Type header [application/x-www-form-urlencoded] is not supported
解决:
curl -XPUT http://node01:9200/blog01/article/1?pretty -d ‘{“id”: “1”, “title”: " What is elasticsearch"}’ -H “Content-Type: application/json”

5、搜索文档

curl -XGET “http://node01:9200/blog01/article/_search?q=title:elasticsearch”

问题:Content-Type header [application/x-www-form-urlencoded] is not supported
解决:
curl -XGET “http://node01:9200/blog01/article/_search?q=title:‘elasticsearch’&pretty” -H “Content-Type: application/json”

6、删除文档

curl -XDELETE “http://node01:9200/blog01/article/1?pretty”

7、删除索引

curl -XDELETE http://node01:9200/blog01?pretty

2、查询条件查询

在kibana提供的界面上进行操作。
POST /school/student/_bulk
{ “index”: { “_id”: 1 }}
{ “name” : “liubei”, “age” : 20 , “sex”: “boy”, “birth”: “1996-01-02” , “about”: “i like diaocan he girl” }
{ “index”: { “_id”: 2 }}
{ “name” : “guanyu”, “age” : 21 , “sex”: “boy”, “birth”: “1995-01-02” , “about”: “i like diaocan” }
{ “index”: { “_id”: 3 }}
{ “name” : “zhangfei”, “age” : 18 , “sex”: “boy”, “birth”: “1998-01-02” , “about”: “i like travel” }
{ “index”: { “_id”: 4 }}
{ “name” : “diaocan”, “age” : 20 , “sex”: “girl”, “birth”: “1996-01-02” , “about”: “i like travel and sport” }
{ “index”: { “_id”: 5 }}
{ “name” : “panjinlian”, “age” : 25 , “sex”: “girl”, “birth”: “1991-01-02” , “about”: “i like travel and wusong” }
{ “index”: { “_id”: 6 }}
{ “name” : “caocao”, “age” : 30 , “sex”: “boy”, “birth”: “1988-01-02” , “about”: “i like xiaoqiao” }
{ “index”: { “_id”: 7 }}
{ “name” : “zhaoyun”, “age” : 31 , “sex”: “boy”, “birth”: “1997-01-02” , “about”: “i like travel and music” }
{ “index”: { “_id”: 8 }}
{ “name” : “xiaoqiao”, “age” : 18 , “sex”: “girl”, “birth”: “1998-01-02” , “about”: “i like caocao” }
{ “index”: { “_id”: 9 }}
{ “name” : “daqiao”, “age” : 20 , “sex”: “girl”, “birth”: “1996-01-02” , “about”: “i like travel and history” }

1、使用match_all做查询

GET /school/student/_search?pretty
{
“query”: {
“match_all”: {}
}
}
问题:通过match_all匹配后,会把所有的数据检索出来,但是往往真正的业务需求并非要找全部的数据,而是检索出自己想要的;并且对于es集群来说,直接检索全部的数据,很容易造成GC现象。所以,我们要学会如何进行高效的检索数据

2、通过关键字段进行查询

GET /school/student/_search?pretty
{
“query”: {
“match”: {“about”: “travel”}
}
}
如果此时想查询喜欢旅游的,并且不能是男孩的,怎么办?
【这种方式是错误的,因为一个match下,不能出现多个字段值[match] query doesn’t support multiple fields】,需要使用复合查询

3、bool的复合查询

当出现多个查询语句组合的时候,可以用bool来包含。bool合并聚包含:must,must_not或者should, should表示or的意思
例子:查询非男性中喜欢旅行的人
GET /school/student/_search?pretty
{
“query”: {
“bool”: {
“must”: { “match”: {“about”: “travel”}},
“must_not”: {“match”: {“sex”: “boy”}}
}
}
}

4、bool的复合查询中的should

should表示可有可无的(如果should匹配到了就展示,否则就不展示)
例子:
查询喜欢旅行的,如果有男性的则显示,否则不显示
GET /school/student/_search?pretty
{
“query”: {
“bool”: {
“must”: { “match”: {“about”: “travel”}},
“should”: {“match”: {“sex”: “boy”}}
}
}
}

5、term匹配

使用term进行精确匹配(比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型))
语法
{ “term”: { “age”: 20 }}
{ “term”: { “date”: “2018-04-01” }}
{ “term”: { “sex”: “boy” }}
{ “term”: { “about”: “trivel” }}
例子:
查询喜欢旅行的
GET /school/student/_search?pretty
{
“query”: {
“bool”: {
“must”: { “term”: {“about”: “travel”}},
“should”: {“term”: {“sex”: “boy”}}
}}
}

6、使用terms匹配多个值

GET /school/student/_search?pretty
{
“query”: {
“bool”: {
“must”: { “terms”: {“about”: [“travel”,“history”]}}
}
}
}
term主要是用于精确的过滤比如说:”我爱你”
在match下面匹配可以为包含:我、爱、你、我爱等等的解析器
在term语法下面就精准匹配到:”我爱你”

7、Range过滤

Range过滤允许我们按照指定的范围查找一些数据:操作范围:gt::大于,gae::大于等于,lt::小于,lte::小于等于
例子:
查找出大于20岁,小于等于25岁的学生
GET /school/student/_search?pretty
{
“query”: {
“range”: {
“age”: {“gt”:20,“lte”:25}
}
}
}

8、exists和 missing过滤

exists和missing过滤可以找到文档中是否包含某个字段或者是没有某个字段
例子:
查找字段中包含age的文档
GET /school/student/_search?pretty
{
“query”: {
“exists”: {
“field”: “age”
}
}
}

9、bool的多条件过滤

用bool也可以像之前match一样来过滤多行条件:
must :: 多个查询条件的完全匹配,相当于 and 。
must_not :: 多个查询条件的相反匹配,相当于 not 。
should :: 至少有一个查询条件匹配, 相当于 or
例子:
过滤出about字段包含travel并且年龄大于20岁小于30岁的同学
GET /school/student/_search?pretty
{
“query”: {
“bool”: {
“must”: [
{“term”: {
“about”: {
“value”: “travel”
}
}},{“range”: {
“age”: {
“gte”: 20,
“lte”: 30
}
}}
]
}
}
}

10、查询与过滤条件合并

通常复杂的查询语句,我们也要配合过滤语句来实现缓存,用filter语句就可以来实现
例子:
查询出喜欢旅行的,并且年龄是20岁的文档
GET /school/student/_search?pretty
{
“query”: {
“bool”: {
“must”: {“match”: {“about”: “travel”}},
“filter”: [{“term”:{“age”: 20}}]
}
}
}

3、定义字段类型mappings

在es当中,每个字段都会有默认的类型,根据我们第一次插入数据进去,es会自动帮我们推断字段的类型,当然我们也可以通过设置mappings来提前自定义我们字段的类型

1、使用mappings来提前定义字段类型

使用mapping的映射管理,提前指定字段的类型,防止后续的程序问题;
DELETE document
PUT document
{
“mappings”: {
“article” : {
“properties”:
{
“title” : {“type”: “text”} ,
“author” : {“type”: “text”} ,
“titleScore” : {“type”: “double”}

  }
}

}
}
get document/article/_mapping

2、基本命令

DELETE school
PUT school
{
“mappings”: {
“logs” : {
“properties”: {“messages” : {“type”: “text”}}
}
}
}
添加索引:school,文档类型类logs,索引字段为message ,字段的类型为text
GET /school/_mapping/logs
继续添加字段
POST /school/_mapping/logs
{
“properties”: {“number” : {“type”: “text”}}
}

GET /school/_mapping/logs

3、获取映射字段

语法:
GET /school/_mapping/logs/field/number

4、管理索引库分片数以及副本数settings

所谓的settings就是用来修改索引分片和副本数的;
比如有的重要索引,副本数很少甚至没有副本,那么我们可以通过setting来添加副本数
DELETE document
PUT document
{
“mappings”: {
“article” : {
“properties”:
{
“title” : {“type”: “text”} ,
“author” : {“type”: “text”} ,
“titleScore” : {“type”: “double”}

  }
}

}
}

GET /document/_settings

可以看到当前的副本数是1,那么为了提高容错性,我们可以把副本数改成2:
PUT /document/_settings
{
“number_of_replicas”: 2
}

副本可以改,分片不能改
PUT /document/_settings
{
“number_of_shards”: 3
}

8、分页解决方案

1、导入数据

DELETE us
POST /_bulk
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “1” }}
{ “email” : “john@smith.com”, “name” : “John Smith”, “username” : “@john” }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “2” }}
{ “email” : “mary@jones.com”, “name” : “Mary Jones”, “username” : “@mary” }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “3” }}
{ “date” : “2014-09-13”, “name” : “Mary Jones”, “tweet” : “Elasticsearch means full text search has never been so easy”, “user_id” : 2 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “4” }}
{ “date” : “2014-09-14”, “name” : “John Smith”, “tweet” : “@mary it is not just text, it does everything”, “user_id” : 1 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “5” }}
{ “date” : “2014-09-15”, “name” : “Mary Jones”, “tweet” : “However did I manage before Elasticsearch?”, “user_id” : 2 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “6” }}
{ “date” : “2014-09-16”, “name” : “John Smith”, “tweet” : “The Elasticsearch API is really easy to use”, “user_id” : 1 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “7” }}
{ “date” : “2014-09-17”, “name” : “Mary Jones”, “tweet” : “The Query DSL is really powerful and flexible”, “user_id” : 2 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “8” }}
{ “date” : “2014-09-18”, “name” : “John Smith”, “user_id” : 1 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “9” }}
{ “date” : “2014-09-19”, “name” : “Mary Jones”, “tweet” : “Geo-location aggregations are really cool”, “user_id” : 2 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “10” }}
{ “date” : “2014-09-20”, “name” : “John Smith”, “tweet” : “Elasticsearch surely is one of the hottest new NoSQL products”, “user_id” : 1 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “11” }}
{ “date” : “2014-09-21”, “name” : “Mary Jones”, “tweet” : “Elasticsearch is built for the cloud, easy to scale”, “user_id” : 2 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “12” }}
{ “date” : “2014-09-22”, “name” : “John Smith”, “tweet” : “Elasticsearch and I have left the honeymoon stage, and I still love her.”, “user_id” : 1 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “13” }}
{ “date” : “2014-09-23”, “name” : “Mary Jones”, “tweet” : “So yes, I am an Elasticsearch fanboy”, “user_id” : 2 }
{ “create”: { “_index”: “us”, “_type”: “tweet”, “_id”: “14” }}
{ “date” : “2014-09-24”, “name” : “John Smith”, “tweet” : “How many more cheesy tweets do I have to write?”, “user_id” : 1 }

2、size+from浅分页

按照一般的查询流程来说,如果我想查询前10条数据:
•1 客户端请求发给某个节点
•2 节点转发给个个分片,查询每个分片上的前10条
•3 结果返回给节点,整合数据,提取前10条
•4 返回给请求客户端
from定义了目标数据的偏移值,size定义当前返回的事件数目
GET /us/_search?pretty
{
“from” : 0 , “size” : 5
}

GET /us/_search?pretty
{
“from” : 5 , “size” : 5
}
这种浅分页只适合少量数据,因为随from增大,查询的时间就会越大,而且数据量越大,查询的效率指数下降
优点:from+size在数据量不大的情况下,效率比较高
缺点:在数据量非常大的情况下,from+size分页会把全部记录加载到内存中,这样做不但运行速递特别慢,而且容易让es出现内存不足而挂掉

3、scroll深分页

对于上面介绍的浅分页,当Elasticsearch响应请求时,它必须确定docs的顺序,排列响应结果。
如果请求的页数较少(假设每页20个docs), Elasticsearch不会有什么问题,但是如果页数较大时,比如请求第20页,Elasticsearch不得不取出第1页到第20页的所有docs,再去除第1页到第19页的docs,得到第20页的docs。
解决的方式就是使用scroll,scroll就是维护了当前索引段的一份快照信息–缓存(这个快照信息是你执行这个scroll查询时的快照)。
可以把 scroll 分为初始化和遍历两步: 1、初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照; 2、遍历时,从这个快照里取数据;
初始化
GET us/_search?scroll=3m
{
“query”: {“match_all”: {}},
“size”: 3
}
初始化的时候就像是普通的search一样
其中的scroll=3m代表当前查询的数据缓存3分钟
Size:3 代表当前查询3条数据
遍历
在遍历时候,拿到上一次遍历中的scrollid,然后带scroll参数,重复上一次的遍历步骤,知道返回的数据为空,就表示遍历完成
GET /_search/scroll
{
“scroll” : “1m”,
“scroll_id” : “DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAPXFk0xN1BmSnlVUldhYThEdWVzZ19xbkEAAAAAAAAAIxZuQWVJU0VSZ1JzcVZtMGVYZ3RDaFlBAAAAAAAAA9oWTVZOdHJ2cXBSOU9wN3c1dk5vcWd4QQAAAAAAAAPYFk0xN1BmSnlVUldhYThEdWVzZ19xbkEAAAAAAAAAIhZuQWVJU0VSZ1JzcVZtMGVYZ3RDaFlB”
}
【注意】:每次都要传参数scroll,刷新搜索结果的缓存时间,另外不需要指定index和type(不要把缓存的时时间设置太长,占用内存)
对比
浅分页,每次查询都会去索引库(本地文件夹)中查询pageNum*page条数据,然后截取掉前面的数据,留下最后的数据。 这样的操作在每个分片上都会执行,最后会将多个分片的数据合并到一起,再次排序,截取需要的。
深分页,可以一次性将所有满足查询条件的数据,都放到内存中。分页的时候,在内存中查询。相对浅分页,就可以避免多次读取磁盘。

9、ES的中文分词器IK

ES默认对英文文本的分词器支持较好,但和lucene一样,如果需要对中文进行全文检索,那么需要使用中文分词器,同lucene一样,在使用中文全文检索前,需要集成IK分词器。那么我们接下来就来安装IK分词器,以实现中文的分词

第一步:三台机器安装IK分词器

将安装包上传到node01机器的/home/es路径下
cd /wph/soft
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.7.0/elasticsearch-analysis-ik-6.7.0.zip

将ik分词器的插件,解压到对应路径下

cd /wph/soft
mkdir -p /wph/install/elasticsearch-6.7.0/plugins/analysis-ik
unzip elasticsearch-analysis-ik-6.7.0.zip -d /wph/install/elasticsearch-6.7.0/plugins/analysis-ik/

将安装包分发到其他机器上
node01机器执行以下命令进行安装包的分发
cd /wph/install/elasticsearch-6.7.0/plugins
scp -r analysis-ik/ node02:PWDscp−ranalysis−ik/node03:PWD scp -r analysis-ik/ node03:PWDscp−ranalysis−ik/node03:PWD

三台机器都配置完成

配置完成之后,需要重启服务。

三台机器重启es服务
三台机器执行以下命令停止es服务并重启es服务
ps -ef|grep elasticsearch | grep bootstrap | awk ‘{print $2}’ |xargs kill -9
nohup /wph/install/elasticsearch-6.7.0/bin/elasticsearch 2>&1 &

第二步、创建索引库并配置IK分词器

delete iktest
PUT /iktest?pretty
{
“settings” : {
“analysis” : {
“analyzer” : {
“ik” : {
“tokenizer” : “ik_max_word”
}
}
}
},
“mappings” : {
“article” : {
“dynamic” : true,
“properties” : {
“subject” : {
“type” : “text”,
“analyzer” : “ik_max_word”
}
}
}
}
}
说明:在创建索引库的时候,我们指定分词方式为ik_max_word,会对我们的中文进行最细粒度的切分

第三步、查看分词效果

在kibana当中执行以下查询,并验证分词效果
GET _analyze?pretty
{
“analyzer”: “ik_max_word”,
“text”: “特朗普是美国总统”
}

第四步、插入测试数据

POST /iktest/article/_bulk?pretty
{ “index” : { “_id” : “1” } }
{“subject” : “"闺蜜"崔顺实被韩检方传唤 韩总统府促彻查真相” }
{ “index” : { “_id” : “2” } }
{“subject” : “韩举行"护国训练" 青瓦台:决不许国家安全出问题” }
{ “index” : { “_id” : “3” } }
{“subject” : “媒体称FBI已经取得搜查令 检视希拉里电邮” }
{ “index” : { “_id” : “4” } }
{“subject” : “村上春树获安徒生奖 演讲中谈及欧洲排外问题” }
{ “index” : { “_id” : “5” } }
{“subject” : “希拉里团队炮轰FBI 参院民主党领袖批其”违法”” }
查看分词器
对"希拉里和韩国"进行分词查询
ikmaxword分词后的效果:希|拉|里|希拉里|和|韩国
POST /iktest/article/_search?pretty
{
“query” : { “match” : { “subject” : “希拉里和韩国” }},
“highlight” : {
“pre_tags” : [""],
“post_tags” : [""],
“fields” : {
“subject” : {}
}
}
}

第五步、配置热词更新

查看分词效果
GET _analyze?pretty
{
“analyzer”: “ik_max_word”,
“text”: “小老弟,你怎么肥事,老铁你来了!!!”
}
我们会发现,随着时间的推移和发展,有些网络热词我们并不能进行分词,因为网络热词并没有定义在我们的词库里面,这就需要我们经常能够实时的更新我们的网络热词,我们可以通过tomcat来实现远程词库来解决这个问题。

1、node03配置Tomcat

使用hadoop用户来进行配置tomcat,此处我们将tomcat装在node03机器上面即可,将我们的tomcat安装包上传到node03服务器的/wph/soft路径下,然后进行解压
cd /wph/soft/
tar -zxf apache-tomcat-8.5.34.tar.gz -C /wph/install/
tomcat当中添加配置hot.dic
cd /wph/install/apache-tomcat-8.5.34/webapps/ROOT
vi hot.dic

老铁
肥事
启动tomcat
cd /wph/install/apache-tomcat-8.5.34/
bin/startup.sh

浏览器访问以验证tomcat是否安装成功
wget http://node03:8080/hot.dic
如果能够访问到,则证明tomcat安装成功

2、 三台机器修改配置文件

三台机器都要修改es的配置文件(使用es用户来进行修改即可)
第一台机器node01修改es的配置
cd /wph/install/elasticsearch-6.7.0/plugins/analysis-ik/config
vim IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?> IK Analyzer 扩展配置 http://node03:8080/hot.dic 修改完成之后拷贝到node02与node03机器上面去 node01执行以下命令进行拷贝 cd /wph/install/elasticsearch-6.7.0/plugins/analysis-ik/config scp IKAnalyzer.cfg.xml node02:$PWD scp IKAnalyzer.cfg.xml node03:$PWD

3、三台机器重新启动es

三台机器重新启动es服务,三台机器先使用kill -9杀死es的服务,然后再执行以下命令进行重启
ps -ef|grep elasticsearch | grep bootstrap | awk ‘{print $2}’ |xargs kill -9
nohup /wph/install/elasticsearch-6.7.0/bin/elasticsearch 2>&1 &
在kibana当中执行以下命令,查看我们的分词过程
GET _analyze?pretty
{
“analyzer”: “ik_max_word”,
“text”: “小老弟,你怎么肥事,老铁你来了”
}

10、Elasticsearch的JavaAPI操作

1:创建maven工程,并添加jar包坐标依赖

创建maven工程,并导入以下jar包坐标依赖

org.elasticsearch.client
transport
6.7.0

org.apache.logging.log4j
log4j-core
2.9.1

org.junit.jupiter
junit-jupiter-api
5.3.0-M1
test

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version>
</dependency>

org.apache.maven.plugins maven-compiler-plugin 1.8 1.8

2:添加索引文件操作

1、创建Client

private TransportClient client;
@BeforeEach
public void test1() throws UnknownHostException {
Settings settings = Settings.builder().put(“cluster.name”, “myes”).build();
client = new PreBuiltTransportClient(settings).addTransportAddress(new TransportAddress(InetAddress.getByName(“node01”),9300)).addTransportAddress(new TransportAddress(InetAddress.getByName(“node02”),9300));
}

2、自己拼装json创建索引保存到myindex1索引库下面的article当中去

/**

  • 插入json格式的索引数据
    */
    @Test
    public void createIndex(){
    String json = “{” +
    ““user”:“kimchy”,” +
    ““postDate”:“2013-01-30”,” +
    ““message”:“travelying out Elasticsearch”” +
    “}”;
    IndexResponse indexResponse = client.prepareIndex(“myindex1”, “article”, “1”).setSource(json, XContentType.JSON).get();
    client.close();
    }

3、使用map创建索引

@Test
public void index2() throws Exception {
HashMap<String, String> jsonMap = new HashMap<String, String>();
jsonMap.put(“name”, “zhangsan”);
jsonMap.put(“sex”, “1”);
jsonMap.put(“age”, “18”);
jsonMap.put(“address”, “bj”);
IndexResponse indexResponse = client.prepareIndex(“myindex1”, “article”, “2”)
.setSource(jsonMap)
.get();
client.close();
}

4、XcontentBuilder实现创建索引

/**

  • 通过XContentBuilder来实现索引的创建
  • @throws IOException
    */
    @Test
    public void index3() throws IOException {
    IndexResponse indexResponse = client.prepareIndex(“myindex1”, “article”, “3”)
    .setSource(new XContentFactory().jsonBuilder()
    .startObject()
    .field(“name”, “lisi”)
    .field(“age”, “18”)
    .field(“sex”, “0”)
    .field(“address”, “bj”)
    .endObject())
    .get();
    client.close();

}

5、将对象转换为json格式字符串进行创建索引

定义person对象
public class Person implements Serializable{
private Integer id;
private String name ;
private Integer age;
private Integer sex;
private String address;
private String phone;
private String email;
private String say;

public Person() {
}public Person(Integer id, String name, Integer age, Integer sex, String address, String phone, String email,String say) {this.id = id;this.name = name;this.age = age;this.sex = sex;this.address = address;this.phone = phone;this.email = email;this.say = say;
}public String getSay() {return say;
}public void setSay(String say) {this.say = say;
}public Integer getId() {return id;
}public void setId(Integer id) {this.id = id;
}public String getName() {return name;
}public void setName(String name) {this.name = name;
}public Integer getAge() {return age;
}public void setAge(Integer age) {this.age = age;
}public Integer getSex() {return sex;
}public void setSex(Integer sex) {this.sex = sex;
}public String getAddress() {return address;
}public void setAddress(String address) {this.address = address;
}public String getPhone() {return phone;
}public void setPhone(String phone) {this.phone = phone;
}public String getEmail() {return email;
}public void setEmail(String email) {this.email = email;
}

}
插入索引数据
/**

  • 将java对象转换为json格式字符串进行创建索引
    */
    @Test
    public void objToIndex(){
    Person person = new Person();
    person.setAge(18);
    person.setId(20);
    person.setName(“张三丰”);
    person.setAddress(“武当山”);
    person.setEmail(“zhangsanfeng@163.com”);
    person.setPhone(“18588888888”);
    person.setSex(1);
    String json = JSONObject.toJSONString(person);
    System.out.println(json);
    client.prepareIndex(“myindex1”,“article”,“32”).setSource(json,XContentType.JSON).get();
    client.close();
    }

6、批量创建索引

/**

  • 批量创建索引
  • @throws IOException
    */
    @Test
    public void index4() throws IOException {
    BulkRequestBuilder bulk = client.prepareBulk();
    bulk.add(client.prepareIndex(“myindex1”, “article”, “4”)
    .setSource(new XContentFactory().jsonBuilder()
    .startObject()
    .field(“name”, “wangwu”)
    .field(“age”, “18”)
    .field(“sex”, “0”)
    .field(“address”, “bj”)
    .endObject()));
    bulk.add(client.prepareIndex(“news”, “article”, “5”)
    .setSource(new XContentFactory().jsonBuilder()
    .startObject()
    .field(“name”, “zhaoliu”)
    .field(“age”, “18”)
    .field(“sex”, “0”)
    .field(“address”, “bj”)
    .endObject()));
    BulkResponse bulkResponse = bulk.get();
    System.out.println(bulkResponse);
    client.close();
    }

3、查询索引

1、初始化一批数据到索引库中准备查询

/**

  • 初始化一批数据到索引库当中去准备做查询使用

  • 注意这里初始化的时候,需要给我们的数据设置分词属性

  • @throws Exception
    */
    @Test
    public void createIndexBatch() throws Exception {
    Settings settings = Settings
    .builder()
    .put(“cluster.name”, “myes”) //节点名称, 在es配置的时候设置
    //自动发现我们其他的es的服务器
    .put(“client.transport.sniff”, “true”)
    .build();
    //创建客户端
    TransportClient client = new PreBuiltTransportClient(settings)
    .addTransportAddress(new TransportAddress(InetAddress.getByName(“node01”), 9300));//以本机作为节点
    //创建映射
    XContentBuilder mapping = XContentFactory.jsonBuilder()
    .startObject()
    .startObject(“properties”)
    // .startObject(“m_id”).field(“type”,“keyword”).endObject()
    .startObject(“id”).field(“type”, “integer”).endObject()
    .startObject(“name”).field(“type”, “text”).field(“analyzer”, “ik_max_word”).endObject()
    .startObject(“age”).field(“type”, “integer”).endObject()
    .startObject(“sex”).field(“type”, “text”).field(“analyzer”, “ik_max_word”).endObject()
    .startObject(“address”).field(“type”, “text”).field(“analyzer”, “ik_max_word”).endObject()
    .startObject(“phone”).field(“type”, “text”).endObject()
    .startObject(“email”).field(“type”, “text”).endObject()
    .startObject(“say”).field(“type”, “text”).field(“analyzer”, “ik_max_word”).endObject()
    .endObject()
    .endObject();
    //pois:索引名 cxyword:类型名(可以自己定义)
    PutMappingRequest putmap = Requests.putMappingRequest(“indexsearch”).type(“mysearch”).source(mapping);
    //创建索引
    client.admin().indices().prepareCreate(“indexsearch”).execute().actionGet();
    //为索引添加映射
    client.admin().indices().putMapping(putmap).actionGet();

    BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
    Person lujunyi = new Person(2, “玉麒麟卢俊义”, 28, 1, “水泊梁山”, “17666666666”, “lujunyi@163.com”,“hello world今天天气还不错”);
    Person wuyong = new Person(3, “智多星吴用”, 45, 1, “水泊梁山”, “17666666666”, “wuyong@163.com”,“行走四方,抱打不平”);
    Person gongsunsheng = new Person(4, “入云龙公孙胜”, 30, 1, “水泊梁山”, “17666666666”, “gongsunsheng@163.com”,“走一个”);
    Person guansheng = new Person(5, “大刀关胜”, 42, 1, “水泊梁山”, “17666666666”, “wusong@163.com”,“我的大刀已经饥渴难耐”);
    Person linchong = new Person(6, “豹子头林冲”, 18, 1, “水泊梁山”, “17666666666”, “linchong@163.com”,“梁山好汉”);
    Person qinming = new Person(7, “霹雳火秦明”, 28, 1, “水泊梁山”, “17666666666”, “qinming@163.com”,“不太了解”);
    Person huyanzhuo = new Person(8, “双鞭呼延灼”, 25, 1, “水泊梁山”, “17666666666”, “huyanzhuo@163.com”,“不是很熟悉”);
    Person huarong = new Person(9, “小李广花荣”, 50, 1, “水泊梁山”, “17666666666”, “huarong@163.com”,“打酱油的”);
    Person chaijin = new Person(10, “小旋风柴进”, 32, 1, “水泊梁山”, “17666666666”, “chaijin@163.com”,“吓唬人的”);
    Person zhisheng = new Person(13, “花和尚鲁智深”, 15, 1, “水泊梁山”, “17666666666”, “luzhisheng@163.com”,“倒拔杨垂柳”);
    Person wusong = new Person(14, “行者武松”, 28, 1, “水泊梁山”, “17666666666”, “wusong@163.com”,“二营长。。。。。。”);

    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “1”)
    .setSource(JSONObject.toJSONString(lujunyi), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “2”)
    .setSource(JSONObject.toJSONString(wuyong), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “3”)
    .setSource(JSONObject.toJSONString(gongsunsheng), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “4”)
    .setSource(JSONObject.toJSONString(guansheng), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “5”)
    .setSource(JSONObject.toJSONString(linchong), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “6”)
    .setSource(JSONObject.toJSONString(qinming), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “7”)
    .setSource(JSONObject.toJSONString(huyanzhuo), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “8”)
    .setSource(JSONObject.toJSONString(huarong), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “9”)
    .setSource(JSONObject.toJSONString(chaijin), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “10”)
    .setSource(JSONObject.toJSONString(zhisheng), XContentType.JSON)
    );
    bulkRequestBuilder.add(client.prepareIndex(“indexsearch”, “mysearch”, “11”)
    .setSource(JSONObject.toJSONString(wusong), XContentType.JSON)
    );

    bulkRequestBuilder.get();
    client.close();

}

2、通过数据id使用prepareGet来查询索引

通过id来进行查询索引
/**

  • 通过id来进行精确查询
    */
    @Test
    public void query1() {
    GetResponse documentFields = client.prepareGet(“indexsearch”, “mysearch”, “11”).get();
    String index = documentFields.getIndex();
    String type = documentFields.getType();
    String id = documentFields.getId();
    System.out.println(index);
    System.out.println(type);
    System.out.println(id);
    Map<String, Object> source = documentFields.getSource();
    for (String s : source.keySet()) {
    System.out.println(source.get(s));
    }
    }

3、查询索引库当中的所有数据

/**

  • 查询所有数据
    */
    @Test
    public void queryAll() {
    SearchResponse searchResponse = client
    .prepareSearch(“indexsearch”)
    .setTypes(“mysearch”)
    .setQuery(new MatchAllQueryBuilder())
    .get();
    SearchHits searchHits = searchResponse.getHits();
    SearchHit[] hits = searchHits.getHits();
    for (SearchHit hit : hits) {
    String sourceAsString = hit.getSourceAsString();
    System.out.println(sourceAsString);
    }
    client.close();
    }

4、RangeQuery范围值查询

查找索引库当中年龄为18到28的所有人
/**

  • 查找年龄18到28的人,包含18和28
    */
    @Test
    public void rangeQuery(){
    SearchResponse searchResponse = client.prepareSearch(“indexsearch”)
    .setTypes(“mysearch”)
    .setQuery(new RangeQueryBuilder(“age”).gt(17).lt(29))
    .get();
    SearchHits hits = searchResponse.getHits();
    SearchHit[] hits1 = hits.getHits();
    for (SearchHit documentFields : hits1) {
    System.out.println(documentFields.getSourceAsString());
    }
    client.close();
    }

5、termQuery词条查询

/**

  • 词条查询
    */
    @Test
    public void termQuery(){
    SearchResponse searchResponse = client.prepareSearch(“indexsearch”).setTypes(“mysearch”)
    .setQuery(new TermQueryBuilder(“say”, “熟悉”))
    .get();
    SearchHits hits = searchResponse.getHits();
    SearchHit[] hits1 = hits.getHits();
    for (SearchHit documentFields : hits1) {
    System.out.println(documentFields.getSourceAsString());
    }
    }

6、fuzzyQuery模糊查询

模糊查询可以自动帮我们纠正写错误的英文单词,最大纠正次数两次
/**

  • fuzzyQuery表示英文单词的最大可纠正次数,最大可以自动纠正两次
    */
    @Test
    public void fuzzyQuery(){
    SearchResponse searchResponse = client.prepareSearch(“indexsearch”).setTypes(“mysearch”)
    .setQuery(QueryBuilders.fuzzyQuery(“say”, “helOL”).fuzziness(Fuzziness.TWO))
    .get();
    SearchHits hits = searchResponse.getHits();
    SearchHit[] hits1 = hits.getHits();
    for (SearchHit documentFields : hits1) {
    System.out.println(documentFields.getSourceAsString());
    }
    client.close();
    }

7、wildCardQuery通配符查询

:匹配任意多个字符
?:仅匹配一个字符
/
*

  • 模糊匹配查询有两种匹配符,分别是" * " 以及 " ? “, 用” * “来匹配任何字符,包括空字符串。用” ? “来匹配任意的单个字符
    /
    @Test
    public void wildCardQueryTest(){
    SearchResponse searchResponse = client.prepareSearch(“indexsearch”).setTypes(“mysearch”)
    .setQuery(QueryBuilders.wildcardQuery(“say”, "hel
    ”))
    .get();
    SearchHits hits = searchResponse.getHits();
    SearchHit[] hits1 = hits.getHits();
    for (SearchHit documentFields : hits1) {
    System.out.println(documentFields.getSourceAsString());
    }
    client.close();
    }

8、boolQuery 多条件组合查询

使用boolQuery实现多条件组合查询
查询年龄是18到28范围内且性别是男性的,或者id范围在10到13范围内的
/**

  • 多条件组合查询 boolQuery

  • 查询年龄是18到28范围内且性别是男性的,或者id范围在10到13范围内的
    */
    @Test
    public void boolQueryTest(){
    RangeQueryBuilder age = QueryBuilders.rangeQuery(“age”).gt(17).lt(29);
    TermQueryBuilder sex = QueryBuilders.termQuery(“sex”, “1”);
    RangeQueryBuilder id = QueryBuilders.rangeQuery(“id”).gt(“9”).lt(“15”);

    SearchResponse searchResponse = client.prepareSearch(“indexsearch”).setTypes(“mysearch”)
    .setQuery(
    QueryBuilders.boolQuery().should(id)
    .should(QueryBuilders.boolQuery().must(sex).must(age)))
    .get();
    SearchHits hits = searchResponse.getHits();
    SearchHit[] hits1 = hits.getHits();
    for (SearchHit documentFields : hits1) {
    System.out.println(documentFields.getSourceAsString());
    }
    client.close();
    }

9、分页与高亮查询

1、分页查询

/*分页查询
*/
@Test
public void getPageIndex(){
int pageSize = 5;
int pageNum = 2;
int startNum = (pageNum-1)*5;
SearchResponse searchResponse = client.prepareSearch(“indexsearch”)
.setTypes(“mysearch”)
.setQuery(QueryBuilders.matchAllQuery())
.addSort(“id”,SortOrder.ASC)
.setFrom(startNum)
.setSize(pageSize)
.get();
SearchHits hits = searchResponse.getHits();
SearchHit[] hits1 = hits.getHits();
for (SearchHit documentFields : hits1) {
System.out.println(documentFields.getSourceAsString());
}
client.close();
}

2、高亮查询

在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮
百度搜索关键字"周星驰"

京东商城搜索"笔记本"

3、高亮显示的html分析

通过开发者工具查看高亮数据的html代码实现:

ElasticSearch可以对查询出的内容中关键字部分进行标签和样式的设置,但是你需要告诉ElasticSearch使用什么标签对高亮关键字进行包裹

4、高亮显示代码实现

/**

  • 高亮查询
    */
    @Test
    public void highLight(){
    //设置我们的查询高亮字段
    SearchRequestBuilder searchRequestBuilder = client.prepareSearch(“indexsearch”)
    .setTypes(“mysearch”)
    .setQuery(QueryBuilders.termQuery(“say”, “hello”));

    //设置我们字段高亮的前缀与后缀
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field(“say”).preTags("").postTags("");

    //通过高亮来进行我们的数据查询
    SearchResponse searchResponse = searchRequestBuilder.highlighter(highlightBuilder).get();
    SearchHits hits = searchResponse.getHits();
    System.out.println(“查询出来一共”+ hits.totalHits+“条数据”);
    for (SearchHit hit : hits) {
    //打印没有高亮显示的数据
    System.out.println(hit.getSourceAsString());
    System.out.println("=========================");
    //打印我们经过高亮显示之后的数据
    Text[] says = hit.getHighlightFields().get(“say”).getFragments();
    for (Text say : says) {
    System.out.println(say);
    }

    /* Map<String, HighlightField> highlightFields = hit.getHighlightFields();
    System.out.println(highlightFields);*/
    }
    client.close();
    }

4、更新索引

根据系统给数据生成的id来进行更新索引
/**

  • 更新索引
  • 根据数据id来进行更新索引
    */
    @Test
    public void updateIndex(){
    Person guansheng = new Person(5, “宋江”, 88, 0, “水泊梁山”, “17666666666”, “wusong@wph.com”,“及时雨宋江”);
    client.prepareUpdate().setIndex(“indexsearch”).setType(“mysearch”).setId(“5”)
    .setDoc(JSONObject.toJSONString(guansheng),XContentType.JSON)
    .get();
    client.close();
    }

5、删除索引

1、按照id进行删除

/**

  • 按照id进行删除数据
    */
    @Test
    public void deleteById(){
    DeleteResponse deleteResponse = client.prepareDelete(“indexsearch”, “mysearch”, “14”).get();
    client.close();
    }

2、按照查询条件来进行删除

/*
按照条件进行删除
*/
@Test
public void deleteByQuery(){

BulkByScrollResponse bulkByScrollResponse = DeleteByQueryAction.INSTANCE.newRequestBuilder(client).filter(QueryBuilders.rangeQuery("id").gt(2).lt(4)).source("indexsearch").get();
long deleted = bulkByScrollResponse.getDeleted();
System.out.println(deleted);

}

3、删除整个索引库

/**

  • 删除索引
  • 删除整个索引库
    */
    @Test
    public void deleteIndex(){
    DeleteIndexResponse indexsearch = client.admin().indices().prepareDelete(“indexsearch”).execute().actionGet();
    client.close();
    }

11、es的高级javaAPI操作

现有结构化数据内容如下:
name age salary team position
张云雷 26 2000 war pf
特斯拉 20 500 tim sf
于谦 25 2000 cav pg
爱迪生 40 1000 tim pf
爱因斯坦 21 300 tim sg
郭德纲 33 3000 cav sf
牛顿 21 500 tim c
岳云鹏 29 1000 war pg

初始化一批数据到es索引库当中去
/**
* 批量添加数据
* @throws IOException
* @throws ExecutionException
* @throws InterruptedException
*/
@Test
public void addIndexDatas() throws IOException, ExecutionException, InterruptedException {
//获取settings
//配置es集群的名字
Settings settings = Settings.builder().put(“cluster.name”, “myes”).build();
//获取客户端
TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(“node01”), 9300);

    TransportAddress transportAddress2 = new TransportAddress(InetAddress.getByName("node02"), 9300);TransportAddress transportAddress3 = new TransportAddress(InetAddress.getByName("node03"), 9300);//获取client客户端TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(transportAddress).addTransportAddress(transportAddress2).addTransportAddress(transportAddress3);/*** 创建索引* */client.admin().indices().prepareCreate("player").get();//构建json的数据格式,创建映射XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject("player").startObject("properties").startObject("name").field("type","text").field("index", "true").field("fielddata","true").endObject().startObject("age").field("type","integer").endObject().startObject("salary").field("type","integer").endObject().startObject("team").field("type","text").field("index", "true").field("fielddata","true").endObject().startObject("position").field("type","text").field("index", "true").field("fielddata","true").endObject().endObject().endObject().endObject();PutMappingRequest request = Requests.putMappingRequest("player").type("player").source(mappingBuilder);client.admin().indices().putMapping(request).get();//批量添加数据开始BulkRequestBuilder bulkRequest = client.prepareBulk();

// either use client#prepare, or use Requests# to directly build index/delete requests
bulkRequest.add(client.prepareIndex(“player”, “player”, “1”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “郭德纲”)
.field(“age”, 33)
.field(“salary”,3000)
.field(“team” , “cav”)
.field(“position” , “sf”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “2”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “于谦”)
.field(“age”, 25)
.field(“salary”,2000)
.field(“team” , “cav”)
.field(“position” , “pg”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “3”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “岳云鹏”)
.field(“age”, 29)
.field(“salary”,1000)
.field(“team” , “war”)
.field(“position” , “pg”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “4”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “孙越”)
.field(“age”, 26)
.field(“salary”,2000)
.field(“team” , “war”)
.field(“position” , “sg”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “5”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “张云雷”)
.field(“age”, 26)
.field(“salary”,2000)
.field(“team” , “war”)
.field(“position” , “pf”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “6”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “爱迪生”)
.field(“age”, 40)
.field(“salary”,1000)
.field(“team” , “tim”)
.field(“position” , “pf”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “7”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “牛顿”)
.field(“age”, 21)
.field(“salary”,500)
.field(“team” , “tim”)
.field(“position” , “c”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “4”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “爱因斯坦”)
.field(“age”, 21)
.field(“salary”,300)
.field(“team” , “tim”)
.field(“position” , “sg”)
.endObject()
)
);
bulkRequest.add(client.prepareIndex(“player”, “player”, “8”)
.setSource(jsonBuilder()
.startObject()
.field(“name”, “特斯拉”)
.field(“age”, 20)
.field(“salary”,500)
.field(“team” , “tim”)
.field(“position” , “sf”)
.endObject()
)
);

    BulkResponse bulkResponse = bulkRequest.get();client.close();
}

需求一:统计每个球队当中球员的数量
sql语句实现
select team, count(*) as player_count from player group by team;
使用javaAPI实现
@Test
public void groupAndCount() {
//1:构建查询提交
SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);
//2:指定聚合条件
TermsAggregationBuilder team = AggregationBuilders.terms(“player_count”).field(“team”);
//3:将聚合条件放入查询条件中
builder.addAggregation(team);
//4:执行action,返回searchResponse
SearchResponse searchResponse = builder.get();
Aggregations aggregations = searchResponse.getAggregations();
for (Aggregation aggregation : aggregations) {
StringTerms stringTerms = (StringTerms) aggregation;
List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
for (StringTerms.Bucket bucket : buckets) {
System.out.println(bucket.getKey());
System.out.println(bucket.getDocCount());
}
}
}

需求二:统计每个球队中每个位置的球员数量
sql语句实现
select team, position, count(*) as pos_count from player group by team, position;
java代码实现
/**

  • 统计每个球队中每个位置的球员数量
    */
    @Test
    public void teamAndPosition(){
    SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);
    TermsAggregationBuilder team = AggregationBuilders.terms(“player_count”).field(“team”);
    TermsAggregationBuilder position = AggregationBuilders.terms(“posititon_count”).field(“position”);
    team.subAggregation(position);
    SearchResponse searchResponse = builder.addAggregation(team).addAggregation(position).get();
    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
    // System.out.println(aggregation.toString());
    StringTerms stringTerms = (StringTerms) aggregation;
    List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
    for (StringTerms.Bucket bucket : buckets) {
    long docCount = bucket.getDocCount();
    Object key = bucket.getKey();
    System.out.println(“当前队伍名称为” + key + “该队伍下有”+docCount + “个球员”);

         Aggregation posititon_count = bucket.getAggregations().get("posititon_count");if(null != posititon_count){StringTerms positionTrem = (StringTerms) posititon_count;List<StringTerms.Bucket> buckets1 = positionTrem.getBuckets();for (StringTerms.Bucket bucket1 : buckets1) {Object key1 = bucket1.getKey();long docCount1 = bucket1.getDocCount();System.out.println("该队伍下面的位置为" +  key1+"该位置下有" +  docCount1 +"人");}}}
    

    }
    }

需求三:分组求各种值
计算每个球队年龄最大值
select team, max(age) as max_age from player group by team;
/**

  • 计算每个球队年龄最大值
    */
    @Test
    public void groupAndMax(){
    SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);
    TermsAggregationBuilder team = AggregationBuilders.terms(“team_group”).field(“team”);

    MaxAggregationBuilder age = AggregationBuilders.max(“max_age”).field(“age”);

    team.subAggregation(age);
    SearchResponse searchResponse = builder.addAggregation(team).get();
    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
    StringTerms stringTerms = (StringTerms) aggregation;
    List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
    for (StringTerms.Bucket bucket : buckets) {
    Aggregation max_age = bucket.getAggregations().get(“max_age”);
    System.out.println(max_age.toString());
    }
    }
    }

需求四:统计每个球队年龄最小值
计算每个球队年龄最大/最小/总/平均的球员年龄
select team, min(age) as min_age from player group by team;
/**

  • 统计每个球队中年龄最小值
    */
    @Test
    public void teamMinAge(){

    SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);

    TermsAggregationBuilder team = AggregationBuilders.terms(“team_count”).field(“team”);

    MinAggregationBuilder age = AggregationBuilders.min(“min_age”).field(“age”);

    TermsAggregationBuilder termAggregation = team.subAggregation(age);

    SearchResponse searchResponse = builder.addAggregation(termAggregation).get();
    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
    System.out.println(aggregation.toString());

     StringTerms stringTerms = (StringTerms) aggregation;List<StringTerms.Bucket> buckets = stringTerms.getBuckets();for (StringTerms.Bucket bucket : buckets) {Aggregations aggregations1 = bucket.getAggregations();for (Aggregation aggregation1 : aggregations1) {System.out.println(aggregation1.toString());}}
    

    }
    }

需求五:分组求平均值
计算每个球队年龄最大/最小/总/平均的球员年龄
select team, avg(age) as max_age from player group by team;
/**

  • 计算每个球队的年龄平均值
    */
    @Test
    public void avgTeamAge(){
    SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);

    TermsAggregationBuilder team_field = AggregationBuilders.terms(“player_count”).field(“team”);

    AvgAggregationBuilder age_avg = AggregationBuilders.avg(“age_avg”).field(“age”);

    team_field.subAggregation(age_avg);

    SearchResponse searchResponse = builder.addAggregation(team_field).get();

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
    System.out.println(aggregation.toString());
    StringTerms stringTerms = (StringTerms) aggregation;
    }

}

需求六:分组求和
计算每个球队球员的平均年龄,同时又要计算总年薪
select team, avg(age)as avg_age, sum(salary) as total_salary from player group by team;
/**

  • 统计每个球队当中的球员平均年龄,以及队员总年薪
    */
    @Test
    public void avgAndSum(){
    SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);

    TermsAggregationBuilder team_group = AggregationBuilders.terms(“team_group”).field(“team”);

    AvgAggregationBuilder avg_age = AggregationBuilders.avg(“avg_age”).field(“age”);

    SumAggregationBuilder sumMoney = AggregationBuilders.sum(“sum_money”).field(“salary”);

    TermsAggregationBuilder termsAggregationBuilder = team_group.subAggregation(avg_age).subAggregation(sumMoney);

    SearchResponse searchResponse = builder.addAggregation(termsAggregationBuilder).get();
    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
    System.out.println(aggregation.toString());
    }

}

需求七:聚合排序
计算每个球队总年薪,并按照总年薪倒序排列
/**

  • 计算每个球队总年薪,并按照年薪进行排序
  • select team, sum(salary) as total_salary from player group by team order by total_salary desc;
    

*/
@Test
public void orderBySum(){
SearchRequestBuilder builder = client.prepareSearch(“player”).setTypes(“player”);
TermsAggregationBuilder teamGroup = AggregationBuilders.terms(“team_group”).field(“team”).order(BucketOrder.count(true));
SumAggregationBuilder sumSalary = AggregationBuilders.sum(“sum_salary”).field(“salary”);
TermsAggregationBuilder termsAggregationBuilder = teamGroup.subAggregation(sumSalary);
SearchResponse searchResponse = builder.addAggregation(termsAggregationBuilder).get();

Map<String, Aggregation> stringAggregationMap = searchResponse.getAggregations().asMap();
System.out.println(stringAggregationMap.toString());
Aggregations aggregations = searchResponse.getAggregations();
for (Aggregation aggregation : aggregations) {System.out.println(aggregation.toString());
}

}

12、ES当中的地理位置搜索

ES不仅可以对我们的数据进行聚合操作,还可以针对我们的地理位置经纬度进行搜索,可以通过ES搜索我们附近的人等等各种基于地理位置的需求
经纬度在线解析网站
http://www.gpsspg.com/maps.htm

第一步:创建索引库并添加数据

直接在kibana当中通过以下操作创建索引库,并添加一条数据
PUT platform_foreign_website
{
“mappings”: {
“store”:{
“properties”: {
“id”: {
“type”: “text”
},
“storeName”: {
“type”: “text”
},
“location”:{
“type”: “geo_point”
}
}
}
}
}

添加数据

40.0488115498,116.4320345091
PUT /platform_foreign_website/store/40?pretty
{“id”: “40”, “storeName”: “北京市北京市朝阳区清河营东路2号院”,“longitude”:116.4320345091,“latitude”:40.0488115498,“isdelete”:true,“location”:{
“lat”:40.0488115498,
“lon”:116.4320345091

}
}

40.0461174292,116.4360685514
PUT /platform_foreign_website/store/41?pretty
{“id”: “40”, “storeName”: “北京市北京市朝阳区北苑东路”,“longitude”:116.4360685514,“latitude”:40.0461174292,“isdelete”:false,“location”:{
“lat”:40.0461174292,
“lon”:116.4360685514

}
}

40.0519526142,116.4178513254
PUT /platform_foreign_website/store/42?pretty
{“id”: “42”, “storeName”: “北京市北京市朝阳区立通路”,“longitude”:116.4178513254,“latitude”:40.0519526142,“isdelete”:true,“location”:{
“lat”:40.0519526142,
“lon”:116.4178513254

}
}

40.0503813013,116.4562592119
PUT /platform_foreign_website/store/43?pretty
{“id”: “43”, “storeName”: “北京市北京市朝阳区来广营北路”,“longitude”:116.4562592119,“latitude”:40.0503813013,“isdelete”:false,“location”:{
“lat”:40.0503813013,
“lon”:116.4562592119

}
}

40.0385828363,116.4465266673
PUT /platform_foreign_website/store/44?pretty
{“id”: “44”, “storeName”: “北京市北京市朝阳区顺白路”,“longitude”:116.4465266673,“latitude”:40.0385828363,“isdelete”:false,“location”:{
“lat”:40.0385828363,
“lon”:116.4465266673

}
}

查询所有的数据
GET /platform_foreign_website/store/_search?pretty
{
“query”: {
“match_all”: {}
}
}

第二步:添加以下jar包坐标依赖

org.locationtech.spatial4j spatial4j 0.6 com.vividsolutions jts 1.13 xerces xercesImpl

这里说了 geo_distance(找出与指定位置在给定距离内的点) 和 geo_polygon(找出落在多边形中的点)两种方法,elasticsearch其实还有另外两种 方法 geo_bounding_box(找出落在指定矩形框中的坐标点) 和 geo_distance_range(找出与指定点距离在给定最小距离和最大距离之间的点),因为需求没有涉及到暂时没有调研,以后会慢慢晚上

第三步:使用javaAPI来实现基于地理位置的搜索

http://www.gpsspg.com/maps.htm
经纬度在线解析

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

public class ESOperate {
public static void main(String[] args) throws UnknownHostException {
Settings settings = Settings.builder()
.put(“cluster.name”, “myes”)
.build();

    TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new TransportAddress(InetAddress.getByName("node03"), 9300));/*** 找出落在指定矩形框当中的坐标点*40.0519526142,116.417851325440.0385828363,116.4465266673*/SearchResponse searchResponse = client.prepareSearch("platform_foreign_website").setTypes("store").setQuery(QueryBuilders.geoBoundingBoxQuery("location").setCorners(40.0519526142, 116.4178513254, 40.0385828363, 116.4465266673)).get();for(SearchHit searchHit : searchResponse.getHits().getHits()) {System.out.println(searchHit.getSourceAsString());}/**|* 找出坐落在多边形当中的坐标点** 40.0519526142,116.4178513254**          40.0519526142,116.4178513254**          40.0385828363,116.4465266673***/List<GeoPoint> points = new ArrayList<GeoPoint>();points.add(new GeoPoint(40.0519526142, 116.4178513254));points.add(new GeoPoint(40.0519526142, 116.4178513254));points.add(new GeoPoint(40.0385828363, 116.4465266673));searchResponse = client.prepareSearch("platform_foreign_website").setTypes("store").setQuery(QueryBuilders.geoPolygonQuery("location", points)).get();for(SearchHit searchHit : searchResponse.getHits().getHits()) {System.out.println(searchHit.getSourceAsString());}System.out.println("==================================================");/*** 以当前的点为中心,搜索落在半径范围内200公里的经纬度坐标点*40.0488115498,116.4320345091*/searchResponse = client.prepareSearch("platform_foreign_website").setTypes("store").setQuery(QueryBuilders.geoDistanceQuery("location").point(40.0488115498, 116.4320345091).distance(200, DistanceUnit.KILOMETERS)).get();for(SearchHit searchHit : searchResponse.getHits().getHits()) {System.out.println(searchHit.getSourceAsString());}client.close();
}

}

13、elasticsearch 的sql插件使用

对于这些复杂的查询,es使用javaAPI都可以实现,但是相较于sql语句来说,我们更加熟悉sql语句,所以es也提供了sql语句的开发,让我们通过sql语句即可实现ES的查询,接下来我们就来安装并学习sql的插件的使用方法吧!
在es版本6.3之前都不支持sql语句的开发,如果需要使用sql语句来开发es的数据查询,那么我们需要手动的自己安装插件,插件下载地址如下,
https://github.com/NLPchina/elasticsearch-sql/
但是在6.3版本之后,es自带就安装了sql的插件,我们可以直接通过sql语句的方式实现es当中的数据查询
对于sql语句的使用,es给我们提供了三种方式,接下来我们分别看看三种方式如何实现es数据的查询

第一种方式:通过rest风格实现数据的查询

第一步:使用rest方式向索引库当中添加数据

使用kibana向索引库当中添加数据
PUT /library/book/_bulk?refresh
{“index”:{"_id": “Leviathan Wakes”}}
{“name”: “Leviathan Wakes”, “author”: “James S.A. Corey”, “release_date”: “2011-06-02”, “page_count”: 561}
{“index”:{"_id": “Hyperion”}}
{“name”: “Hyperion”, “author”: “Dan Simmons”, “release_date”: “1989-05-26”, “page_count”: 482}
{“index”:{"_id": “Dune”}}
{“name”: “Dune”, “author”: “Frank Herbert”, “release_date”: “1965-06-01”, “page_count”: 604}

第二步:使用rest风格方式查询数据

curl -X POST “node01:9200/_xpack/sql?format=txt” -H ‘Content-Type: application/json’ -d’
{
“query”: “SELECT * FROM library WHERE release_date < \u00272000-01-01\u0027”
}’

第二种方式:使用sql脚本的方式进入sql客户端进行查询

我们也可以使用sql脚本的方式,进入sql客户端,通过sql语句的方式实现数据的查询

第一步:node01进入sql脚本客户端

node01执行以下命令进入sql脚本客户端
cd /wph/install/elasticsearch-6.7.0
bin/elasticsearch-sql-cli node01:9200

第二步:执行sql语句

sql> select * from library;
author | name | page_count | release_date
----------------±--------------±--------------±-----------------------
Dan Simmons |Hyperion |482 |1989-05-26T00:00:00.000Z
James S.A. Corey|Leviathan Wakes|561 |2011-06-02T00:00:00.000Z
Frank Herbert |Dune |604 |1965-06-01T00:00:00.000Z

第三种方式:通过jdbc连接的方式

当然了,我们也可以通过jdbc连接的方式,通过java代码来实现ES当中数据的查询操作
官网介绍操作连接
https://www.elastic.co/guide/en/elasticsearch/reference/6.7/sql-jdbc.html

使用javaAPI访问数据库当中的数据,会产生一个错误,参见这篇文章
https://www.cnblogs.com/hts-technology/p/9282421.html

第一步:导入jar包

在我们的maven依赖中添加以下坐标,导入es-sql的jar包

elastic.co
https://artifacts.elastic.co/maven

<dependency><groupId>org.elasticsearch.plugin</groupId><artifactId>x-pack-sql-jdbc</artifactId><version>6.7.0</version></dependency>

第二步:开发java代码,实现查询

通过java代码,使用jdbc连接es服务器,然后查询数据

@Test
public void esJdbc() throws SQLException {
EsDataSource dataSource = new EsDataSource();
String address = “jdbc

Elasticsearch进阶笔记相关推荐

  1. 数据库-Elasticsearch进阶学习笔记(分片、映射、分词器、即时搜索、全文搜索等)

    目录 基础概念 定义 特点 索引(Index) 分片(Shards) 副本(Replicas) 分配(Allocation) 映射(Mapping) 动态映射 显式映射 常见数据类型 文档(docum ...

  2. 数据库-Elasticsearch进阶学习笔记(集群、故障、扩容、简繁体、拼音等)

    目录 集群 集群配置 单节点集群 分布式集群 故障转移 水平扩容 路由计算&分片控制 数据CRUD流程 写流程 读流程 更新流程 删除流程 分词器 IK分词器 Pinyin分词器 简繁体转换器 ...

  3. Elasticsearch进阶

    本文: 不谈搜索引擎的原理: 不谈倒排索引的原理: 不谈乐观锁.悲观锁的机制: -- 只谈: 从产品开发.项目实战的角度,如何让一个 Java 程序员甚至 C/C++ 的程序员快速上手. 海量的版本中 ...

  4. Docker基础、进阶笔记,为k8s的学习预预热

    标题 Docker基础.进阶笔记,为k8s的学习预预热 笔记来源于视频: 狂神docker基础篇 狂神docker进阶篇 笔记中图片有些取自于:这位博主的两篇docker笔记中的一些图片 百度云笔记工 ...

  5. Android进阶笔记:Messenger源码详解

    Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...

  6. Android进阶笔记:AIDL内部实现详解 (二)

    接着上一篇分析的aidl的流程解析.知道了aidl主要就是利用Ibinder来实现跨进程通信的.既然是通过对Binder各种方法的封装,那也可以不使用aidl自己通过Binder来实现跨进程通讯.那么 ...

  7. Shell 编程进阶笔记

    这几篇博文主要记录博主的Linux 学习之路,用作以后回顾和参考.大家可以选择略过也可以作参考. (一)Linux 初步笔记 (二)Linux 进阶笔记(一) (三)Linux 进阶笔记(二) (四) ...

  8. Linux 进阶笔记(二)

    这几篇博文主要记录博主的Linux 学习之路,用作以后回顾和参考.大家可以选择略过也可以作参考. (一)Linux 初步笔记 (二)Linux 进阶笔记(一) (三)Linux 进阶笔记(二) (四) ...

  9. Linux 进阶笔记(一)

    这几篇博文主要记录博主的Linux 学习之路,用作以后回顾和参考.大家可以选择略过也可以作参考. (一)Linux 初步笔记 (二)Linux 进阶笔记(一) (三)Linux 进阶笔记(二) (四) ...

最新文章

  1. Linux 磁盘坏道检测和修复
  2. Python爬虫(十三)_JSON模块与JsonPath
  3. OpenCV cv::reduce用法的实例(附完整代码)
  4. 实验7.2 二维数组 7-4 判断上三角矩阵
  5. 【开源】.Net Api开放接口文档网站
  6. Petya and Staircases CF212div.2B
  7. java403forbidden_java – Spring boot – 返回403 Forbidden而不是重定向到登录页面
  8. 四大猛壳之一的VMProtect轻松保护你的程序
  9. 在软件测试中UT,IT,ST,UAT分别是什么意思
  10. stm32F4系列3:学习资料和教程推荐,流程推荐。
  11. 电子电路学习笔记(16)——晶振电路的电容
  12. Windows内核原理与实现之Windows设备驱动程序
  13. 战争英雄、同性恋和计算机科学的奠基人
  14. github电脑壁纸_GitHub - githubtaotao/bing-wallpaper: Bing每日壁纸,自动获取Bing的精美图片设置为壁纸,并且支持随机切换历史壁纸,查看壁纸故事...
  15. iOS开发之3D Touch(快速添加3D Touch功能)
  16. html5 tooltip,HTML5 教程之CSS 提示工具(Tooltip)
  17. MySQL拷贝表结构、表数据总结
  18. 美元指数升至七周高点 短期仍有上涨动能
  19. 华为路由器登录方式设置
  20. JavaScript之事件触发on和事件监听addEvent及addEventListener的区别和作用

热门文章

  1. Vim中的常用命令总结(持续补充完善)
  2. 腾讯云服务器被黑客挂pnscan病毒排查
  3. 整理的CAPL详细内容
  4. zzulioj1166实数取整(指针专题)
  5. 运筹学实验8 最短路的求解
  6. 晨光BT——强大的资源分享网站
  7. Mongodb数据库教程
  8. 【C++】C/C++内存管理
  9. ORACLE R12 Workflow Mailer设置
  10. 莫烦Python视频笔记