ElasticSearch详细笔记( 从入门到入土)

文章目录


1.ElasticSearch概述

1.1 Elasticsearch 是什么

image-20220411232454470

1.2 全文搜索引擎

​ Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时 候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日 志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。

一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进 行全文检索需要扫描整个表,如果数据量大的话即使对 SQL 的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。

基于以上原因可以分析得出,在一些生产环境中,使用常规的搜索方式,性能是非常差 的。

1.3 Elasticsearch And Solr

Lucene 是 Apache 软件基金会 Jakarta 项目组的一个子项目,提供了一个简单却强大的 应用程式接口,能够做全文索引和搜寻。在 Java 开发环境里 Lucene 是一个成熟的免费开源 工具。就其本身而言,Lucene 是当前以及最近几年最受欢迎的免费 Java 信息检索程序库。 但 Lucene 只是一个提供全文搜索功能类库的核心工具包,而真正使用它还需要一个完善的 服务框架搭建起来进行应用。

目前市面上流行的搜索引擎软件,主流的就两款:ElasticsearchSolr,这两款都是基 于 Lucene 搭建的,可以独立部署启动的搜索引擎服务软件。由于内核相同,所以两者除了 服务器安装、部署、管理、集群以外,对于数据的操作 修改、添加、保存、查询等等都十 分类似。

image-20220411233145419

2. ElasticSearch安装

2.1 下载和安装

Elasticsearch 的官方地址:https://www.elastic.co/cn/

直接下载window版本即可

Windows 版的 Elasticsearch 的安装很简单,解压即安装完毕,解压后的 Elasticsearch 的 目录结构如下

image-20220411233411235

image-20220411233431014

解压后,进入 bin 文件目录,点击 elasticsearch.bat 文件启动 ES 服务

image-20220411233453298

注意:9300端口为 Elasticsearch 集群间组件的通信端口,9200 端口为浏览器访问的 http 协议 RESTful 端口。

打开浏览器(推荐使用谷歌浏览器),输入地址:http://localhost:9200,测试结果

image-20220411234425710

2.2 可能存在的问题

Elasticsearch 是使用 java 开发的,且 7.8 版本的 ES 需要 JDK 版本 1.8 以上,默认安装 包带有 jdk 环境,如果系统配置 JAVA_HOME,那么使用系统默认的 JDK,如果没有配 置使用自带的 JDK,一般建议使用系统配置的 JDK。

双击启动窗口闪退,通过路径访问追踪错误,如果是“空间不足”,请修改config/jvm.options 配置文件

image-20220411234818062

2.3 RESTful

在 REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目 标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET、POST、 PUT、DELETE,还可能包括 HEAD 和 OPTIONS。简单的理解就是,如果想要访问互联 网上的资源,就必须向资源所在的服务器发出请求,请求体中必须包含资源的网络路径,以 及对资源进行的操作(增删改查)

get,put,delete具有幂等性,即向ES服务器多次发送同一个url,操作是相当的;而post没有幂等性,多次发送的请求不同

3. ES的基本使用

3.1 数据格式

Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解, 我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比

image-20220411235014948

ES 里的 Index 可以看做一个库,而 Types 相当于表,Documents 则相当于表的行。 这里 Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包含一个 type,Elasticsearch 7.X 中, Type 的概念已经被删除了。

文档以Json形式存储,比如一条用户信息

{
   
 "name" : "John",
 "sex" : "Male",
 "age" : 25,
 "birthDate": "1990/05/01",
 "about" : "I love to go rock climbing",
 "interests": [ "sports", "music" ]
}

3.2 分片概念

简单来讲就是咱们在ES中所有数据的文件块,也是数据的最小单元块,整个ES集群的核心就是对所有分片的分布、索引、负载、路由等达到惊人的速度

实列场景:假设 IndexA 有2个分片,我们向 IndexA 中插入10条数据 (10个文档),那么这10条数据会尽可能平均的分为5条存储在第一个分片,剩下的5条会存储在另一个分片中。

image-20220412000443069

image-20220412000750641

3.3 索引操作

(1)创建索引

对比关系型数据库,创建索引就等同于创建数据库

向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/shopping

image-20220412001039611

{
   
 "acknowledged"【响应结果】: true, # true 操作成功
 "shards_acknowledged"【分片结果】: true, # 分片操作成功
 "index"【索引名称】: "shopping"
}
# 注意:创建索引库的分片数默认 1 片,在 7.0.0 之前的 Elasticsearch 版本中,默认 5

如果重复添加索引,会返回错误信息

image-20220412001111720

(2) 查看所有索引

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/_cat/indices?v

这里请求路径中的_cat 表示查看的意思,indices 表示索引,所以整体含义就是查看当前 ES 服务器中的所有索引,就好像 MySQL 中的 show tables 的感觉,服务器响应结果如下

image-20220412001337834

image-20220412001349719

(3) 查看单个索引

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/shopping

image-20220412001454608

{
   
     "shopping"【索引名】: {
   
     	"aliases"【别名】: {
   },
     	"mappings"【映射】: {
   },
     	"settings"【设置】: {
   
    		 "index"【设置 - 索引】: {
   
                 "creation_date"【设置 - 索引 - 创建时间】: "1614265373911",
                 "number_of_shards"【设置 - 索引 - 主分片数量】: "1",
                 "number_of_replicas"【设置 - 索引 - 副分片数量】: "1",
                 "uuid"【设置 - 索引 - 唯一标识】: "eI5wemRERTumxGCc1bAk2A",
                 "version"【设置 - 索引 - 版本】: {
   
                 "created": "7080099"
                 },
                "provided_name"【设置 - 索引 - 名称】: "shopping"
     		}
    	 }
     }
}

(4) 删除索引

向 ES 服务器发 DELETE 请求 :http://127.0.0.1:9200/shopping

image-20220412001748372

重新访问索引时,服务器返回响应:索引不存在

image-20220412001821710

3.4 文档操作

(1)创建文档

索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数 据库中的表数据,添加的数据格式为 JSON 格式

向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/shopping/_doc

请求体内容为:

{
   
 "title":"小米手机",
 "category":"小米",
 "images":"http://www.gulixueyuan.com/xm.jpg",
 "price":3999.00
}

image-20220412002017597

此处发送请求的方式必须为 POST,不能是 PUT,否则会发生错误

{
   
     "_index"【索引】: "shopping",
     "_type"【类型-文档】: "_doc",
     "_id"【唯一标识】: "Xhsa2ncBlvF_7lxyCE9G", #可以类比为 MySQL 中的主键,随机生成
     "_version"【版本】: 1,
     "result"【结果】: "created", #这里的 create 表示创建成功
     "_shards"【分片】: {
   
     "total"【分片 - 总数】: 2,
     "successful"【分片 - 成功】: 1,
     "failed"【分片 - 失败】: 0
     },
     "_seq_no": 0,
     "_primary_term": 1
}

上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下,ES 服务器会随机 生成一个。 如果想要自定义唯一性标识,需要在创建时指定:http://127.0.0.1:9200/shopping/_doc/1

image-20220412002239868

此处需要注意:如果增加数据时明确数据主键,那么请求方式也可以为 PUT

(2) 查看文档

查看文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/shopping/_doc/1

image-20220412002653926

(3)修改文档

和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖

向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/shopping/_doc/1

请求体内容为:

{
   
     "title":"华为手机",
     "category":"华为",
     "images":"http://www.gulixueyuan.com/hw.jpg",
     "price":4999.00
}

image-20220412003002331

(4) 修改字段

修改数据时,也可以只修改某一给条数据的局部信息

向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/shopping/_update/1

注意全体修改为_doc,修改字段为_update

请求体内容为:

{
   
     "doc": {
   
     "price":3000.00
     }
}

image-20220412003154188

(6)删除文档

删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)

向 ES 服务器发 DELETE 请求 :http://127.0.0.1:9200/shopping/_doc/1

image-20220412003344517

{
   
     "_index": "shopping",
     "_type": "_doc",
     "_id": "1",
     "_version"【版本】: 4, #对数据的操作,都会更新版本
     "result"【结果】: "deleted", # deleted 表示数据被标记为删除
     "_shards": {
   
     "total": 2,
     "successful": 1,
     "failed": 0
     },
     "_seq_no": 4,
     "_primary_term": 2
}

(6) 条件删除文档

一般删除数据都是根据文档的唯一性标识进行删除,实际操作时,也可以根据条件对多条数据进行删除

首先分别增加多条数据:

{
   
     "title":"小米手机",
     "category":"小米",
     "images":"http://www.gulixueyuan.com/xm.jpg",
     "price":4000.00
}
{
   
     "title":"华为手机",
     "category":"华为",
     "images":"http://www.gulixueyuan.com/hw.jpg",
     "price":4000.00
}

向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/shopping/_delete_by_query

请求体内容为:

{
   
     "query":{
   
         "match":{
   
             "price":4000.00
         }
     }
}

image-20220412132224680

3.5 映射操作

有了索引库,等于有了数据库中的 database。

接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。 创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型 下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。

(1) 创建映射

先创建一个索引student,然后添加映射

向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/student/_mapping

请求体内容为:

{
   
     "properties": {
   
         "name":{
   
             "type": "text",
             "index": true
         },
         "sex":{
   
             "type": "text",
             "index": false
         },
         "age":{
   
             "type": "long",
             "index": false
         }
     }
}

image-20220412135701369

映射数据说明:

  1. 字段名:任意填写,下面指定许多属性,例如:title、subtitle、images、price

  2. type:类型,Elasticsearch 中支持的数据类型非常丰富,说几个关键的:

    ​ (1)String 类型,又分两种:

    • text:可分词
    • keyword:不可分词,数据会作为完整字段进行匹配

    ​ (2)Numerical:数值类型,分两类

    • 基本数据类型:long、integer、short、byte、double、float、half_float
    • 浮点数的高精度类型:scaled_floatwww

    ​ (3)Date:日期类型

    ​ (4)Array:数组类型

    ​ (5) Object:对象

  3. index:是否索引,默认为 true,也就是说你不进行任何配置,所有字段都会被索引

    true:字段会被索引,则可以用来进行搜索

    false:字段不会被索引,不能用来搜索

  4. store:是否将数据进行独立存储,默认为 false

    原始的文本会存储在_source 里面,默认情况下其他提取出来的字段都不是独立存储 的,是从_source 里面提取出来的。当然你也可以独立的存储某个字段,只要设置 “store”: true 即可,获取独立存储的字段要比从_source 中解析快得多,但是也会占用 更多的空间,所以要根据实际业务需求来设置。

  5. analyzer:分词器,这里的 ik_max_word 即使用 ik 分词器

(2) 查看映射

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_mapping

image-20220412142402086

(3) 索引映射关联

即在创建索引的时候即添加映射要求

创建一个student1索引,添加映射要求如下:

{
   
     "settings": {
   },
     "mappings": {
   
         "properties": {
   
            "name":{
   
                 "type": "text",
                 "index": true
            },
            "sex":{
   
                 "type": "text",
                 "index": false
            },
            "age":{
   
                 "type": "long",
                 "index": false
            }
         }
     }
}

向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/student1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GCT91ui-1650284771661)(https://gitee.com/GOV_D/my-picture/raw/master/MyPicture/image-20220412142729141.png)]

3.6 文档高级查询

(1) 查询所有文档

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search

或者带请求体,但全匹配,即查出所有文档

{
   
     "query": {
   
         "match_all": {
   }
     }
}
// "query":这里的 query 代表一个查询对象,里面可以有不同的查询属性
// "match_all":查询类型,例如:match_all(代表查询所有), match,term , range 等等
// {查询条件}:查询条件会根据类型的不同,写法也有差异

image-20220412143512791

{
   
     "took【查询花费时间,单位毫秒】" : 1116,
     "timed_out【是否超时】" : false,
     "_shards【分片信息】" : {
   
         "total【总数】" : 1,
         "successful【成功】" : 1,
         "skipped【忽略】" : 0,
         "failed【失败】" : 0
     },
     "hits【搜索命中结果】" : {
   
         "total"【搜索条件匹配的文档总数】: {
   
         "value"【总命中计数的值】: 3,
         "relation"【计数规则】: "eq" // eq 表示计数准确, gte 表示计数不准确
    	 },
         "max_score【匹配度分值】" : 1.0,
         "hits【命中结果集合】" : [
             。。。
         }
     	]
     }
}

(2) 匹配查询

match 匹配类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是 or 的关系

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/shooping/_search

{
   
     "query": {
   
         "match": {
   
              "category":"小米"
         }
     }
}

多字段匹配查询,即查询条件可以在多个字段中去进行匹配

multi_match 与 match 类似,不同的是它可以在多个字段中查询。

向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/shooping/_search

{
   
     "query": {
   
         "multi_match": {
   
         "query": "小米",
         "fields": ["tile","category"]
         }
     }
}
//即title或者category字段中包含小米即可被查出

(3)完全匹配查询

精确的关键词匹配查询,不对查询条件进行分词

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,

{
   
 "query":{
   
		"match_phrase":{
   
			"category" : "华为"
		}
	}
}

(4)查询指定字段

如果只想查询指定的某个字段,比如只需要title

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"query":{
   
		"match_all":{
   }
	},
	"_source":["title"]
}

(5)分页查询

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"query":{
   
		"match_all":{
   }
	},
	"from":0, //起始页
	"size":2 //页的大小
}

(6)查询排序

如果你想对查询结果进行排序,如根据价格降序排序

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"query":{
   
		"match_all":{
   }
	},
	"sort":{
   
		"price":{
   
			"order":"desc"
		}
	}
}

(7)多条件查询

假设想找出小米牌子并且价格为3999元的。(must相当于数据库的&&)

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"query":{
   
		"bool":{
   
			"must":[{
   
				"match":{
   
					"category":"小米"
				}
			},{
   
				"match":{
   
					"price":3999.00
				}
			}]
		}
	}
}

假设想找出小米或华为的牌子,即满足一个条件即可。(should相当于数据库的||)

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"query":{
   
		"bool":{
   
			"should":[{
   
				"match":{
   
					"category":"小米"
				}
			},{
   
				"match":{
   
					"category":"华为"
				}
			}]
		}
	}
}

(8)范围查询

假设想找出小米或华为的牌子,价格大于2000元的手机。

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"query":{
   
		"bool":{
   
			"should":[{
   
				"match":{
   
					"category":"小米"
				}
			},{
   
				"match":{
   
					"category":"华为"
				}
			}],
            "filter":{
   
            	"range":{
   
                	"price":{
   
                    	"gt":2000
                	}
	            }
    	    }
		}
	}
}

(9)高亮查询

即在查询结果中将查询条件高亮

{
   
	"query":{
   
		"match_phrase":{
   
			"category" : "华为"
		}
	},
    "highlight":{
   
        "fields":{
   
            "category":{
   }//<----高亮这字段
        }
    }
}

(10)聚合查询

聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很多其他的聚合,例如取最大值max、平均值avg等等。

如按price字段进行分组:

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"aggs":{
   //聚合操作
		"price_group":{
   //名称,随意起名
			"terms":{
   //分组
				"field":"price"//分组字段
			}
		}
	}
}

上面返回结果会附带原始数据的。若不想要不附带原始数据的结果,只想要统计结果

向 ES 服务器发 GET请求 :http://127.0.0.1:9200/shopping/_search

{
   
	"aggs":{
   
		"price_group":{
   
			"terms":{
   
				"field":"price"
			}
		}
	},
    "size":0
}

若想对所有手机价格求平均值

向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search

{
   
	"aggs":{
   
		"price_avg":{
   //名称,随意起名
			"avg":{
   //求平均
				"field":"price"
			}
		}
	},
    "size":0
}

4. Java操作ES

4.1 环境搭建

maven依赖:

<dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.8.0</version>
        </dependency>
        <!-- elasticsearch 的客户端 -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.8.0</version>
        </dependency>
        <!-- elasticsearch 依赖 2.x 的 log4j -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.17.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <!-- junit 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

试试建立连接

public class Es_client {
   
    public static void main(String[] args) throws IOException {
   
        //创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost",9200,"http"))
        );

        //释放连接
        client.close();
    }
}

Java通过API操作ES也不过是封装了原生的restful请求罢了,其响应结果也和直接使用restful去请求是一样的

4.2 索引操作

(1)创建索引

public class EsClient_index_create {
   
    public static void main(String[] args) throws IOException {
   
        //创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost",9200,"http"))
        );
        // 创建索引 - 请求对象
        CreateIndexRequest request = new CreateIndexRequest("user");
        // 发送请求,获取响应
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        //输出创建状态
        System.out.println(response.isAcknowledged());

        //释放连接
        client.close();
    }
}

(2)查询索引

public class EsClient_index_get {
   
    public static void main(String[] args) throws IOException {
   
        //创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost",9200,"http"))
        );
        // 要发送的某种类型的请求
        GetIndexRequest request = new GetIndexRequest("user");
        // 发送请求,获取响应
        GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
        //输出响应结果
        System.out.println("aliases:"+response.getAliases());
        System.out.println("mappings:"+response.getMappings());
        System.out.println("settings:"+response.getSettings());

        //释放连接
        client.close()
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值