当前位置:   article > 正文

ElasticSearch从入门到精通--第一话(入门篇)_es从入门到精通

es从入门到精通

ElasticSearch从入门到精通–第一话

ElasticSearch从入门到精通–第一话(入门篇)
ElasticSearch从入门到精通–第二话(原生API调用–纯代码篇)
ElasticSearch从入门到精通–第三话(集群环境搭建篇)
ElasticSearch从入门到精通–第四话(核心概念篇)
ElasticSearch从入门到精通–第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)

基础概念了解:

  • 结构化数据:可以用二维表结构来表示的数据。如关系型数据,一个学生表,存储学生的姓名、性别、年龄等信息,用一些关系型数据库就可以解决(Mysql、Oracle等),但是这些列都是定死的,无法扩展;Mysql后续也引入了json数据类型,提高扩展性,但是使用起来还是有点不太方便的。

  • 非结构化数据:无法用二维表来表示的数据。如视频、日志、文档类数据,可以保存到NoSql非关系型数据库中,如Redis、MongoDB,多以k-v结构存储

  • 半结构数据:如一些xml、json数据可存储到Redis、MongoDB等NoSql数据库,但是查询处理不是那么容易的。

那么海量数据包括结构、非结构数据准确查询,ES就产生了。

入门

Elastic Stack的核心:包括Elasticsearch(存储搜索数据的)、Kibana(展示数据的)、Beats和Logstatch(也被称为是ELK Stack)。

ElasticSearch简称ES,是一个开源的高扩展的分布式全文搜索引擎,是整个Elastic Stack的技术栈的核心。它可以近乎实时存储、检索数据;扩展性很好,可以扩展上百台服务器,处理PB级别的数据。

其实常见的搜索工具除了ES外还有Solr,它们都是在lucene的基础上开发的。两者区别不是很大,但是如果涉及到除了搜索文本外还需要处理分析查询、分布式索引、日志管理、监控和指标等,那么毫无疑问,ES是更好的选择。

下载安装(windows版)

到es官网下载:下载地址

选择下载的产品

在这里插入图片描述

下载Elasticsearch解压缩即可。目录基本上都是能看懂的,bin(可执行文件)、conf(配置)、logs(日志)、jdk

在这里插入图片描述

进入到bin后,执行elasticsearch.bat即可执行es(linux系统是sh文件)。

要注意:9300端口是es集群组件的通信端口,而9200端口是浏览器访问的http协议的Restful端口。启动es后,打开浏览器访问localhost:9200即可。

在这里插入图片描述

问题

  1. 新手入门一般都会遇见的问题:那就是版本问题:
  • ES6版本以下不会提供自带jdk,需要本系统的
  • ES6版本需要JDK8及以上版本(有些版本可能不会自带jdk,使用本系统的即可)
  • ES7版本需要JDK11以上才能使用(自带jdk)
  • ES8目前JDK在18版本上(自带jdk)

可以选择跟自己系统已经安装的jdk匹配的es版本,也可以直接去使用es自带的jdk,而不去使用系统已经安装的(不推荐),在elasticsearch-env.bat文件中,修改(将一些不必要的东西使用 rem注释即可 )

rem if defined JAVA_HOME (
rem  set JAVA="%JAVA_HOME%\bin\java.exe"
rem ) else (
  set JAVA="%ES_HOME%\jdk\bin\java.exe"
  set JAVA_HOME="%ES_HOME%\jdk"
rem )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 还可能遇到双击启动后,窗口闪退问题,通过路径访问追踪错误,如果是空间不足的问题,可以修改config/jvm.options文件,将1g调整为更高的即可。

    # Xms represents the initial size of total heap space
    # Xmx represents the maximum size of total heap space
    
    -Xms1g
    -Xmx1g
    
    • 1
    • 2
    • 3
    • 4
    • 5

相关概念

es是分布式、Restful风格的搜索和分析。

分布式大家应该都了解,像我们做的一些项目,分别部署到不同的服务器上,达到分布式的部署。

Restful就是指满足http协议,不仅可以访问资源,还可以新增、修改、删除一些资源,像我们之前的URI,就是统一资源定位符,只是用来访问一些资源的,而涉及到Restful风格就会具有更多的功能性,请求如:GET、POST、DELETE、HEAD等。这些请求方式会涉及到幂等性问题(访问多次返回的结果如果是一样的,就是幂等性),而PUT、DELETE就是典型的幂等性接口。

ES发出响应的数据就是JSON格式

数据格式&倒排索引

看到很多博客里基本上都是把相关的数据格式跟mysql对应起来学习了,我这边也不例外,来张图了解下

在这里插入图片描述

ES中,Index可以看做是数据库,Type是表,Document是行数据,然后Fields就是列,但是这些概念违背了ES全文索引的原则和基本思想,后来引入一种新的概念:倒排索引。

既然有倒排索引,那么必然就有正排索引,比如在数据库的一张学生表中,有id和name两个字段,我要通过id去查找到相关的name,如果有模糊查询,我要根据name模糊查询就是正排索引;

倒排索引就是我在新的表中,保存着相应的查询关键字和id值(可能是多个值),我根据关键字去找到对应的id们,然后去学生表中查询id即可。

上图中的Type(也就是mysql中的表)概念已经被弱化了,ES6中,现在一个index中只能包含一个type,在ES7中,Type的概念已经被删除了。

索引

创建索引

在ES中创建索引就是创建index,可以通过Postman或现流行的国产ApiFox调用都可。

向ES服务器发送PUT请求:http://localhost:9200/shopping,这个shopping就是index的名称,PUT请求代表是修改的意思。

请求发送后,返回json格式数据,其中index就是索引名称

在这里插入图片描述

如果再次请求,服务器会告知你这个index已经存在了,而且牢记新建索引是不支持POST请求的

查询索引

查询单个索引

向ES服务器发送GET请求:http://localhost:9200/shopping,还是上文中创建的那个索引,只需要把请求方式改为GET即可。

在这里插入图片描述

查询所有索引

向ES服务器发送GET请求:http://localhost:9200/_cat/indices?v,即可展示所有,目前只有一个索引

在这里插入图片描述

删除索引

向ES服务器发送DELETE请求:http://localhost:9200/shopping,即可删除索引

在这里插入图片描述

文档

创建文档

向ES服务器发送POST请求:http://localhost:9200/shopping/_doc,然后在请求体中写入需要的文档数据,发送请求即可。

{
    "title":"手机",
    "category":"小米",
    "img":"http://www.gulixueyuan.com/xm.jpg",
    "price":3900.00
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

而且新增文档成功后,会返回的_id是es服务器生成并返回的,每次新建后都会返回不一样的id,所以要满足非幂等性必须要使用POST方式。

生成自定义id

那么我们肯定不会去使用es生成的id,太难记,我们需要自定义id,当我们自定义id时,每次请求后返回的id肯定是相同的,那么会产生幂等性,那么我们无论是使用PUT还是POST都是可以的。

向ES服务器发送POST请求:http://localhost:9200/shopping/_doc/文档id,然后在请求体中写入需要的文档数据,发送请求即可。

在这里插入图片描述

查询文档

主键id查询

向ES服务器发送GET请求:http://localhost:9200/shopping/_doc/1001,发送请求即可。(1001是上面创建的文档id)

在这里插入图片描述

如果要查询的文档id不存在,那么上图中返回的json数据中,found字段就是false.

全查询

向ES服务器发送GET请求:http://localhost:9200/shopping/_search,发送请求即可

在这里插入图片描述

修改文档

修改分为两种,一种是完全覆盖,一种是修改部分。

全量修改使用PUT请求

向ES服务器发送PUT请求:http://localhost:9200/shopping/_doc/1001,写入所有要修改的字段及值,发送请求即可

要注意的是:全量修改时,如果你把某些字段给删了,那么这些字段就不存在于文档中了

在这里插入图片描述

局部数据更新

向ES服务器发送POST请求:http://localhost:9200/shopping/_update/1001,写入要修改的字段及值,发送请求即可,比如要修改文档中的title属性

{
    "doc":{
        "title":"华为手机"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

删除文档

向ES服务器发送DELETE请求:http://localhost:9200/shopping/_doc/1001,发送请求即可

在这里插入图片描述

如果删除一个不存在的文档,那么会被告知未找到

在这里插入图片描述

查询

根据条件查询

向ES服务器发送GET请求:http://localhost:9200/shopping/_search?q=category:小米,查询所有category是小米的数据

在这里插入图片描述

但是大多情况下,路径中有中文时会被转码,所以请求参数还是要写到请求体中的。

GET请求,访问http://localhost:9200/shopping/_search,带参数

{
    "query":{
        "match":{
            "category":"小米"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

分页查询

同样GET请求访问以上http://localhost:9200/shopping/_search链接,然后请求体中带参数。

{
    "query":{
        "match":{
            "category":"小米"
        }
    },
    "from":0,	// 表示从0的偏移量开始读取
    "size":2	// 读取两条数据
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个和mysql分页是差不多的,一个是偏移量,一个是行数。公式:(pageNo-1)*页面行数

在这里插入图片描述

"_source"中就是返回给我们的数据,那么我只想要一个title怎么限制呢?

直接在请求体中设置_source即可

{
    "query":{
        "match":{
            "category":"小米"
        }
    },
    "from":0,
    "size":2,
    "_source":["title"]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

查询排序

仍然是上面的GET接口,http://localhost:9200/shopping/_search,然后请求体加参数即可。

{
    "query":{
        "match":{
            "category":"小米"
        }
    },
    "from":0,
    "size":2,
    "sort":{
        "price":{	// 以price字段排序,desc降序,asc升序
            "order":"desc"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

多条件查询

和上文中接口一致,只需在请求体参数语法上改变

must可以理解为and,should理解为or。

{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "category":"小米"
                    }
                },
                {
                    "match":{
                        "price":5000
                    }
                }
            ]
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
{
    "query":{
        "bool":{
            "should":[
                {
                    "match":{
                        "category":"小米"
                    }
                },
                {
                    "match":{
                        "category":"华为"
                    }
                }
            ]
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下图为or查询

在这里插入图片描述

范围查询

同上接口,请求体参数改变,以下查询为category是小米或华为的数据,且price大于4500的

{
    "query":{
        "bool":{
            "should":[
                {
                    "match":{
                        "category":"小米"
                    }
                },
                {
                    "match":{
                        "category":"华为"
                    }
                }
            ],
            "filter":{
                "range":{
                    "price":{
                        "gt": 4500
                    }
                }
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

精确查询

在这里插入图片描述

全文检索

当我们保存文档数据时,es会将数据分词拆解,并将拆解后的数据保存到倒排索引当中,即使我们查询时只使用关键词的一部分,那么它还是会被查询出来,就叫做全文检索。

GET请求访问http://localhost:9200/shopping/_search,请求体增加参数

{
    "query":{
        "match":{
            "category":"米"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

那么所有category带字的所有数据会被查询出来,而且查询时的参数也会被进行拆解查询

{
    "query":{
        "match":{
            "category":"米华"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

那么所有category带字的所有数据会被查询出来

当然,也可以进行完全匹配

{
    "query":{
        "match_phrase":{
            "category":"米华"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

必须是米华的才会被查询出来。

查询高亮显示

GET请求访问http://localhost:9200/shopping/_search,请求体增加参数

{
    "query":{
        "match_phrase":{
            "category":"小米"
        }
    },
    "highlight":{	// 设置高亮
        "fields": {		// 高亮的字段
            "category":{}
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

聚合查询

GET请求访问http://localhost:9200/shopping/_search,请求体增加参数

{
    "aggs":{
        "price_group":{ // 分组名称,随意起名
            "terms":{   // 分组
                "field":"price" // 分组字段
            }
        }
    },
    "size": 0 // 表示不展示原始数据,只展示分组后的
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

若要求平均值

{
    "aggs":{
        "price_avg":{ // 名称,随意起名
            "avg":{   // 平均值
                "field":"price" // 求平均值的字段
            }
        }
    },
    "size": 0 // 表示不展示原始数据,只展示分组后的
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

映射关系

映射关系是给index索引设置的。

es6版本http://localhost:9200/user/mapping/_mapping,其他版本http://localhost:9200/user/_mapping

POST请求http://localhost:9200/user/_mapping,请求体中参数

{
    "properties":{
        "name":{
            "type":"text",
            "index":true	// 表示被索引
        },
        "sex":{
            "type":"keyword", //表示不被拆解
            "index":true
        },
        "tel":{
            "type":"keyword",
            "index":false
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

设置后,同一个接口改为GET请求方式,可以查询出刚刚设置的mapping.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BA0mfgxw-1667200229961)(imgs/24.png)]

那么创建一个用户,PUT请求http://localhost:9200/user/_doc/1001,方法体参数

{
    "name":"小米",
    "sex":"男性",
    "tel":"2222"
}
  • 1
  • 2
  • 3
  • 4
  • 5

创建完毕后,查询下试试

GET请求,http://localhost:9200/user/_search,请求体参数

{
    "query":{
        "match":{
            "name":"小"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

刚刚的name属性设置的是text类型,也就是会被拆解,所有name中有字的都会被查询出来,如果是keyword类型,则不会被拆解,如查询sex

{
    "query":{
        "match":{
            "sex":"男"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

那么查询数据为空,而像tel设置的不被索引,当匹配时将会提示报错。

全文检索之copy_to/multi_match

我们还可以在创建索引库时,字段指定copy_to,然后让数据拷贝到某个字段中,然后多字段查询;或者可以使用multi_match进行多字段查询
新建索引时指定copy_to

# 新建索引时,指定copy_to
PUT /test
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text",
        "analyzer": "standard",
        "copy_to": "all"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "all":{
        "type": "text"
      }
    }
  }
}

# 加两条数据
PUT /test/_doc/1001
{
  "name":"天生丽质",
  "brand":"天"
}

PUT /test/_doc/1002
{
  "name":"高贵优雅",
  "brand":"外"
}

# 通过all字段查询
GET /test/_search
{
  "query": {
    "match": {
      "all": "丽外"
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

结果是,name中带的,和brand中带的都会被查询出来
在这里插入图片描述

那么如果不指定all字段,我们还可以通过其他的方式进行多字段匹配查询

GET /test/_search
{
  "query": {
    "multi_match": {
      "query": "丽外",
      "fields": ["brand", "name"]
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
结果只查询出来一条,啊?为啥呢,那么重点来了。我们在定义的索引中all字段用的type类型是text,就是会被分词,但是多条件查询中,brand用的是keyword,不会被分词,copy_to只是将值赋给了all字段,每条伪数据类似如下

{
  "all": ["天生丽质", "天"]
}

{
  "all": ["高贵优雅", "外"]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/310654?site
推荐阅读
相关标签
  

闽ICP备14008679号