Elaticsearch,简称为es, 是一个建立在全文搜索引擎框架 Apache Lucene™ 基础上的开源搜索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。同时Elasticsearch 是使用 Java 编写的,采用了 Lucene 来实现索引与搜索的功能。当你使用它做全文搜索时,只需要使用简单流畅的 RESTful API 即可,并不需要了解 Lucene 背后复杂的的运行原理。(API本质就是一次http请求,可以用任何工具发起http请求)
Elasticsearch安装教程:https://blog.csdn.net/Lzy410992/article/details/114709726
操作索引
Elasticsearch也是基于Lucene的全文检索库,本质也是存储数据,很多概念与MySQL类似的。
对比关系:
索引(indices)------------------------Databases 数据库
类型(type)-------------------------Table 数据表
文档(Document)------------------Row 行
字段(Field)-------------------Columns 列
映射(mapping)-----------------每个列的约束条件
详细说明:
概念 | 说明 |
---|---|
索引 (index) | 一个索引就是一个拥有几分相似特征的文档的集合 |
索引库(indices) | indices是index的复数,代表许多的索引(拥有一些相似性特征的集合) |
类型(type) | 类型是模拟mysql中的table概念,一个索引库下可以有不同类型的索引,比如商品索引,订单索引,其数据格式不同。不过这会导致索引库混乱,因此未来版本中会移除这个概念 |
文档(document) | 存入索引库原始的数据。比如每一条商品信息,就是一个文档 |
字段(field) | 文档中的属性,相当于是数据表的字段,对文档数据根据不同属性进行的分类标识 |
映射配置(mappings) | mapping是处理数据的方式和规则方面做一些限制,如字段的数据类型、属性、是否索引、是否存储等特性 |
集群 (cluster) | 一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。 |
节点 (node) | 节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能 |
分片(shard) | 数据拆分后的各个部分,一个索引可以存储超出单个结点硬件限制的大量数据 |
副本(replica) | 每个分片的复制 |
Elasticsearch本身就是分布式的,因此即便你只有一个节点,Elasticsearch默认也会对你的数据进行分片和副本操作,当你向集群添加新数据时,数据也会在新加入的节点中进行平衡。
ES Restful API 中的VERB
参数 | 作用 |
---|---|
GET | 获取请求对象的当前状态 |
POST | 改变对象的当前状态 |
PUT | 创建一个对象 |
DELETE | 销毁对象 |
HEAD | 请求获取对象的基础信息 |
创建索引的请求格式:
PUT /索引库名
示例:
修改索引的请求格式:
PUT /索引库名/_settings
示例:
查询所有的索引:
GET _cat/indices
示例:
检测集群是否健康:
GET _cat/health
示例:
获取集群的节点列表:
GET _cat/nodes
示例:
查看索引设置请求格式:
GET /索引库名
查看所有索引库配置
GET *
示例:
删除索引请求格式:
DELETE /索引库名
示例:
使用HEAD请求,查看索引是否存在:
HEAD /索引库名
示例:
映射配置
索引有了,接下来肯定是添加数据。但是,在添加数据之前必须定义映射。映射是定义文档的过程,文档包含哪些字段,这些字段是否保存,是否索引,是否分词等,配置清楚映射,Elasticsearch会帮我们进行索引库的创建。
创建映射字段:
PUT /索引库名/_mapping/类型名称
{
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"
}
}
}
- 类型名称:就是前面将的type的概念,类似于数据库中的不同表
字段名:任意填写 ,可以指定许多属性,例如: - type:类型,可以是text、long、short、date、integer、object等
- index:是否索引,默认为true
- store:是否存储,默认为false
- analyzer:分词器,这里的
ik_max_word
即使用ik分词器
字段属性详解:
type:数据类型
-
String类型,分两种:
text:
可分词,不可参与聚合
keyword:
不可分词,数据会作为完整字段进行匹配,可以参与聚合 -
Numerical:数值类型,分两类
基本数据类型:
long、interger、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
,需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。 -
Date:日期类型, elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。
index:影响字段的索引情况
- true:字段会被索引,则可以用来进行搜索。默认值就是true,你不进行任何配置,字段就会被索引
- false:字段不会被索引,不能用来搜索,有些字段是我们不希望被索引的,需要手动设置index为false
store:是否将数据进行额外存储。
Elasticsearch在创建文档索引时,会将文档中的原始数据备份,保存到一个叫做_source
的属性中。而且我们可以通过过滤_source
来选择哪些要显示,哪些不显示。而如果设置store为true,就会在_source
以外额外存储一份数据,多余,因此一般我们都会将store设置为false,事实上,store的默认值就是false。
boost:激励因子,与lucene中一样
示例:发起请求
查看映射关系:
GET /索引库名/_mapping
示例:
新增数据
通过POST请求,可以向一个已经存在的索引库中添加数据。
POST /索引库名/类型名
{
"key":"value"
}
示例:
查询数据:
get _search
{
"query":{
"match_all":{}
}
}
示例:
智能判断: 事实上Elasticsearch非常智能,你不需要给索引库设置任何mapping映射,它也可以根据你输入的数据来判断类型,动态添加数据映射。
测试一下:
POST /ly/goods/2
{
"title":"苹果手机",
"images":"http://image.ly.com/12479122.jpg",
"price":2899.00,
"stock": 200,
"saleable":true
}
额外添加了stock库存,和saleable是否上架两个字段。查看结果:
在看下索引库的映射关系:
修改数据
把刚才新增的请求方式改为PUT,就是修改了。不过修改必须指定id,
- id对应文档存在,则修改
- id对应文档不存在,则新增
删除数据
删除使用DELETE请求,同样,需要根据id进行删除:
DELETE /索引库名/类型名/id值
示例:
查询
基本查询:
GET /索引库名/_search
{
"query":{
"查询类型":{
"查询条件":"查询条件值"
}
}
}
这里的query代表一个查询对象,里面可以有不同的查询属性
- 查询类型:
match_all
,match
,term
,range
等等 - 查询条件:查询条件会根据类型的不同,写法也有差异,后面详细讲解
查询所有(match_all):
示例:
GET /ly/_search
{
"query":{
"match_all": {}
}
}
匹配查询(match):
添加数据,便于测试:
PUT /ly/goods/2
{
"title":"苹果手机",
"images":"http://image.ly.com/12479122.jpg",
"price":3899.00
}
PUT /ly/goods/3
{
"title":"华为手机",
"images":"http://image.ly.com/12479122.jpg",
"price":1899.00
}
PUT /ly/goods/4
{
"title":"小米电视",
"images":"http://image.ly.com/12479122.jpg",
"price":5899.00
}
or关系: match
类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or的关系
GET /heima/_search
{
"query":{
"match":{
"title":"小米电视"
}
}
}
结果:
在上面的案例中,不仅会查询到电视,而且与小米相关的都会查询到,多个词之间是or
的关系。
and关系: 某些情况下,我们需要更精确查找,我们希望这个关系变成and
,可以这样做:
GET /heima/_search
{
"query":{
"match": {
"title": {
"query": "小米电视",
"operator": "and"
}
}
}
}
结果:
本例中,只有同时包含小米
和电视
的词条才会被搜索到。
or和and之间:
在 or
与 and
间二选一有点过于非黑即白。 如果用户给定的条件分词后有 5 个查询词项,想查找只包含其中 4 个词的文档,该如何处理?我们如何获得处于中间的某种结果?
match
查询支持 minimum_should_match
最小匹配参数, 这让我们可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字,更常用的做法是将其设置为一个百分数
,因为我们无法控制用户搜索时输入的单词数量:
GET /ly/_search
{
"query":{
"match":{
"title":{
"query":"小米曲面电视",
"minimum_should_match": "75%"
}
}
}
}
结果:
多字段查询(multi_match):
multi_match
与match
类似,不同的是它可以在多个字段中查询
GET /ly/_search
{
"query":{
"multi_match": {
"query": "小米",
"fields": [ "title", "subTitle" ]
}
}
}
结果:
词条匹配(term):
term
查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些未分词的字符串
GET /heima/_search
{
"query":{
"term":{
"price":2699.00
}
}
}
结果:
多词条精确匹配(terms):
terms
查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件:
GET /ly/_search
{
"query":{
"terms":{
"price":[1899.00,3899.00]
}
}
}
结果:
结果过滤
默认情况下,elasticsearch在搜索的结果中,会把文档中保存在_source
的所有字段都返回。如果我们只想获取其中的部分字段,我们可以添加_source
的过滤
直接指定字段:
示例:
GET /ly/_search
{
"_source": ["title","price"],
"query": {
"term": {
"price": 2699
}
}
}
返回的结果:
指定includes和excludes:
可以通过:
includes:
来指定想要显示的字段excludes:
来指定不想要显示的字段
示例:
GET /ly/_search
{
"_source": {
"includes":["title","price"]
},
"query": {
"term": {
"price": 2699
}
}
}
GET /ly/_search
{
"_source": {
"excludes": ["images"]
},
"query": {
"term": {
"price": 2699
}
}
}
高级查询
布尔组合(bool):
bool
把各种其它查询通过must
(与)、must_not
(非)、should
(或)的方式进行组合
GET /heima/_search
{
"query":{
"bool":{
"must": { "match": { "title": "大米" }},
"must_not": { "match": { "title": "电视" }},
"should": { "match": { "title": "手机" }}
}
}
}
结果:
范围查询(range):
range
查询找出那些落在指定区间内的数字或者时间
GET /heima/_search
{
"query":{
"range": {
"price": {
"gte": 1000.0,
"lt": 2800.00
}
}
}
}
结果:
模糊查询(fuzzy):
fuzzy
查询是 term
查询的模糊等价。它允许用户搜索词条与实际词条的拼写出现偏差,但是偏差的编辑距离不得超过2:
GET /ly/_search
{
"query": {
"fuzzy": {
"title": "appla"
}
}
}
我们可以通过fuzziness
来指定允许的编辑距离:
GET /ly/_search
{
"query": {
"fuzzy": {
"title": {
"value":"appla",
"fuzziness":1
}
}
}
}
结果:
过滤(filter)
条件查询中进行过滤
所有的查询都会影响到文档的评分及排名。如果我们需要在查询结果中进行过滤,并且不希望过滤条件影响评分,那么就不要把过滤条件作为查询条件来用。而是使用filter
方式:
GET /ly/_search
{
"query":{
"bool":{
"must":{ "match": { "title": "小米手机" }},
"filter":{
"range":{"price":{"gt":2000.00,"lt":3800.00}}
}
}
}
}
结果:
注意:filter
中还可以再次进行bool
组合条件过滤。
无查询条件,直接过滤
如果一次查询只有过滤,没有查询条件,不希望进行评分,我们可以使用constant_score
取代只有 filter 语句的 bool 查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助。
GET /ly/_search
{
"query":{
"constant_score": {
"filter": {
"range":{"price":{"gt":2000.00,"lt":4000.00}}
}
}
}
结果:
排序
单字段排序:
sort
可以让我们按照不同的字段进行排序,并且通过order
指定排序的方式
GET /ly/_search
{
"query": {
"match": {
"title": "手机"
}
},
"sort": [
{
"price": {
"order": "desc"
}
}
]
}
多字段排序:
假定我们想要结合使用 price和 _score(得分) 进行查询,并且匹配的结果首先按照价格排序,然后按照相关性得分排序:
GET /goods/_search
{
"query":{
"bool":{
"must":{ "match": { "title": "手机" }},
"filter":{
"range":{"price":{"gt":2000.00,"lt":5000.00}}
}
}
},
"sort": [
{ "price": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
}