elasticsearch小白入门

1,001 阅读16分钟

elasticsearch小白入门

介绍

第一次在掘金发表文章,有些不足之处,求勿喷!求勿喷!求勿喷! 身为一个前端,居然搞es原因在于我们公司内部的wiki文档全栈项目的使用,由于日益增多的文章和想要全文检索的需求,并且原本的mongodb数据库,查询全文检索时特别慢,才引入了es。 车300工具平台,项目目前还没公开出来,预计2021年公开。

起源Lucene

一个叫 Doug Cutting 的美国工程师迷上了搜索引擎,他做了一个用于文本搜索的函数库(软件功能组件),命名为LuceneLuceneJAVA写的,目标是为各种中小型应用软件加入全文检索功能。因为好用且开源,非常受程序员欢迎。 早期是由这个人自己维护,后期做大后,2001年底,成为Apache软件基金会jakarta项目的一个子项目。

Lucene 是一个信息检索工具包,jar包,不包含搜索引擎系统! 包含了:索引结构、读写索引的工具、排序、搜索规则...工具类!

Lucene 和 Elasticsearch

elasticSearch 是基于Lucene 做了一些封装和增强。es是一个开源的、高拓展的、分布式、全文检索引擎。诞生于21世纪大数据时代。(Restful Api)。2016年超过solr,成为排名第一个的搜索引擎类应用。

Elasticsearch历史

多年前,一个叫做Shay Banon刚结婚不久的失业开发者,由于妻子要去伦敦学习厨师,他就跟老婆一起去了,在他找工作的过程中,为了给妻子构建一个食谱搜索引擎,他就开始使用Lucene工具包开发。由于直接使用原生工具包非常麻烦,于是他就开始抽象化Lucene代码写自己的封装,后来他在找到工作后又重写了 自己的封装,并命名为elasticsearch。 再后来,2010年2月,第一个公开版es发布,es在短时间内瞬间成为当时 github 上最受欢迎的项目之一,一家主营es的公司就此成立,他们一边开发新功能,一边提供商用,并永远开源, 遗憾的是,Shay的妻子依然在等待食谱搜索....

什么是搜索?

1)百度,谷歌。我们可以通过输入一些关键字去搜索我们需要的东西。 2)互联网的搜索:电商网站。招聘网站。新闻网站。各种APP(百度外卖,美团等等) 3)windows系统的搜索等等

总结:搜索无处不在。通过一些关键字,给我们查询出来跟这些关键字相关的信息

什么是全文检索?

全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

什么是 Elasticsearch?

使用 java 语言开发的一套开源的全文搜索引擎 用于搜索、日志管理、安全分析、指标分析、业务分析、应用性能监控等多个领域 底层基于 Lucene 开源库开发,提供 restAPI,可以被任何语言调用 支持分布式部署,可水平扩展 更新迭代快、社区活跃、文档丰富(2020年9月写的这篇文章是7.9.1,而现在11月已经7.10.x了)

自行去官网下载 win linux 及其他版本安装包

链接: elasticsearch下载

ik分词器是一个github项目,可以选择git clone 或者 直接download zip

kibana下载

为了方便演示,这边是windows系统下的教程,linux后续推出如何发布线上等等。

熟悉es目录

bin 是启动目录
config 配置文件
--- log4j2 日志配置文件
--- jvm.options java虚拟机相关配置
--- elasticsearch.yml elasticsearch配置文件,默认 9200 端口!
lib 相关jar包
logs 日志
modules 相关模块
plugins 插件如ik

启动

直接访问 bin 目录下 elasticsearch.bat

安装可视化插件 elasticsearch-head

git clone https://github.com/mobz/elasticsearch-head.git

进入目录后

cnpm install 

访问 localhost:9100, 发现跨域问题

去es config目录 的 elasticsearch.yml 添加跨域配置

http.cors.enabled: true 
http.cors.allow-origin: "*" 

*代表所有人都可以访问,实际正式环境不可以这样配置

重启 elasticsearch 这时再访问 localhost:9100 即可

kibana的安装与使用

了解 ELK

了解ELK工程师 ELK是 Elasticsearch Logstash Kibana 三大开源库的简称,市面上也称为 Elastic Stack。其中Elasticsearch是一个基于Lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。像百度、谷歌这种大数据全文搜索引擎的场景都可以使用es这作为底层支持框架,可见es提供的搜索能力确实强大,Logstash 是中央数据流引擎,用于从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过过滤后只支持输出到不同目的地(文件/MQ/redis/es等)。Kibana是一个es可视化工具,提供了实时分析的能力。

收集清洗数据 ---> 搜索,存储 --->Kibana

要保证Kibana版本和es保持一致

kibana的windows下载地址,点击即可下载

启动

kibana-7.9.1-windows-x86_64\bin 目录下的 kibana.bat

|  ![](https://fe.che300.com/easymock/upload/2020/09/22/64a8d5d4abfb5c69f375dc282bdd75fd.png)
|_

访问 5601端口即可访问

ps:开发工具!(postman等等其他的)

修改汉化

去配置文件D:\tools\kibana-7.9.1-windows-x86_64\config\kibana.yml中修改

i18n.locale: "zh-CN"

es核心概念

es是面向文档的非关系数据库

关系型数据库es
数据库索引
types(慢慢被弃用了,7.x.x版本使用统一的_doc,并在查询命令中可以省略)
documents(文档)
字段fields

文档

es是面向文档的,

  • 意味着索引和搜索数据的最小单位是文档,类似关系数据库中某张表中的一行记录(好理解)
  • 文档会被序列化成 JSON 格式,JSON 对象由字段组成(以json格式存储)
  • 每个字段都有对应的字段类型,类型可以自己指定,也可以使用 ElasticSearch 自动推算(智能化)
  • JSON 文档支持数组和嵌套(自由度很高)
  • 每个文档都有一个唯一性 ID,可以自己指定,也可以系统自动生成(智能化)

尽管我们可以随意新增忽略某个字段,但是每个字段的类型非常重要,比如一个年龄类型字段,可以是字符串也可以是整数,因为es中会保存字段和类型之间的映射以及其他的设置,这种映射具体到每个映射的每种类型,这也是为什么在es中,类型有时候也称为映射类型。

一个文档主要元素大致包含以下内容:

1. _index: 文档所属的索引名
2. _type: 文档所属的类型名(废弃品)
3. _id: 文档的唯一ID
4. _source: 文档存储的 Json 数据
5. _version:文档的版本信息
6. _score: 相关性打分

类型

类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。

索引

最直接的理解就是数据库!

  • 每个索引都是一个非常大的文档集合。
  • 每个索引有自己的 Mapping 用于定义文档的字段名和字段类型
  • 每个索引有自己的 Settings 用于定义不同的数据分布,也就是索引使用分片的情况(我没用过👻👻👻)
节点和集群如何工作

一个集群至少有一个节点,而一个节点就是一个es进程,节点可以有多个索引(默认的),如果你创建索引,那么索引将会有5个分片(primary shard,又称主分片)构成的,每一个主分片会有一个副本(replica shard,又称复制分片)

因为不是专职做这个的,所以这里关于这些东西就一带而过了。。。,小白入门不需要了解太多底层吧

倒排索引是什么

es使用的是一种称为倒排索引的结构,采用Lucene倒排索引作为底层,这种结构适用于快速的全文索引,一个索引由文档中所有的不重复的列表构成,对于每一个词,都有一个包含它的文档列表。例如,现在有两个文档,每个文档包含如下内容:

Study every day, good good up, to forever # 文档一
To forever, study every day, good good up # 文档二

为了创建倒排索引,我们要将每个文档拆分成独立的词(词条),然后创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档

现在我们要去搜索 to forever 只需要查看包含每个词条的文档

这里产生了权重!

总结:倒排索引帮我们完全过滤掉了一些无用的数据,帮我们提高了效率

1、索引(数据库) 2、字段类型(mapping) 3、文档 4、分片(了解,Lucene索引)

分词插件(IK分词器)

分词就是把一段中文或者英文划分为一个个关键字,我们在搜索的时候会把自己的信息进行分词,会把数据库中的或者索引库中的数据进行分词,然后进行一个匹配操作做,默认的中文分词是将每一个字看成一个词,比如“我爱育仪”会被分成“我”“爱”“育”“仪”,这里显然是不合理的,所以我们需要安装中文的分词器。 IK提供了两个分词算法:ik_smartik_max_word,其中 ik_smart是最少切分,ik_max_word是最细粒度划分!

附件中有IK分词器的安装包 1、安装 2、直接解压到es安装目录的plugin目录中命名为ik 3、重启es

验证 分词器是否安装完成, 4、使用 elasticsearch-plugin

5、用kibana测试!

ik_smart 最少划分

ik_max_word 最多划分

两种分词器使用的最佳实践是:索引时用ik_max_word,在搜索时用ik_smart。 即:索引时最大化的将文章内容分词,搜索时更精确的搜索到想要的结果。

1、ik_max_word

会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。

2、ik_smart 会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。

发现问题

这种自己需要的词,需要我们自己加上我们的分词器中,才会实现真正的分词

自己添加词典

D:\tools\elasticsearch-7.9.1\plugins\ik\config\IKAnalyzer.cfg.xml(这是我的路径,别人和我不一样的) 在这个目录下修改

|  ![](https://fe.che300.com/easymock/upload/2020/09/22/94b72e0a58ac77eec8dc4ae38da4b2e2.png)
|_

elasticsearch-7.9.1\plugins\ik\config 目录下新建 自定义的词典例如: 1、新建yuyi.dic 2、在 该文件中写入 3、在下图位置加上自己的配置文件名 4、重启es 5、再次测试

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "超级喜欢育仪讲"
}

返回值发生了变化

{
  "tokens" : [
    {
      "token" : "超级",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "喜欢",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "育仪",
      "start_offset" : 4,
      "end_offset" : 6,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "讲",
      "start_offset" : 6,
      "end_offset" : 7,
      "type" : "CN_CHAR",
      "position" : 3
    }
  ]
}

以后需要自己配置,就需要自己在分词中设置即可

Rest 风格说明

这是一种架构风格而不是标准,他用于客户端与服务器交互 类的软件,基于这个风格设计软件可以更简洁、更有层次等。

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/_update/文档id修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id通过文档id查询文档
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

创建文档

示例1
PUT /test1/type1/1
{
  "name":"育仪",
  "age":24
}

类型名未来在 8版本中会被删除

示例2
PUT /test3/_doc/1
{
  "name":"育仪分享会",
  "age":24,
  "birth":"1996-09-12"
}

这里的_doc是未来es官方指定的类型,未来将去掉类型名称,统一为一个系统指定的_doc

如果我们没有指定 文档类型,es默认会帮我们指定类型

字段指定类型

  • 字符串类型:text、keyword
  • 数值类型:long、integer、short、byte、double、float、half float、scaled float
  • 日期类型:date
  • te布尔类型:boolean
  • 二进制类型:binary
  • 等等......

测试

PUT /test2
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "age":{
        "type": "long"
      },
      "birthday":{
        "type": "date"
      }
    }
  }
}

返回上图则成功

mappings、properties为指定字段类型的必须格式,内部的name、age、birthday为用户想要的类型,类似mysql的建表。

通过get请求获取信息

GET /test2

可以通过get请求,直接获取test2索引的全部信息

拓展:通过命令 查看 es 索引情况

查看数据库健康值

GET _cat/health

查看es很多信息

GET _cat/indices?v

等等还有很多

修改

修改提交还是使用PUT 然后覆盖即可!(曾经的方法)

PUT /test3/_doc/1
{
  "name":"育仪分享会20200921",
  "age":24,
  "birth":"1996-09-12"
}

这种修改更新方式是整体修改,一旦丢掉数据则会产生修改错误的字段

更新的方法(新的)

POST /test3/_update/1
{
  "doc":{
    "name":"育仪大魔王"
  }
}

更新成功,再调用查看方法即可发现就name字段发生了变化。 值得注意的是 doc是固定写法

删除

删除整个索引

DELETE /test1

返回值:

删除一条数据

Delete /test3/_doc/1

使用RESTFUL风格是我们ES推荐大家使用的!

关于文档的操作

基本操作

1、先创建一个索引并加入数据

PUT /yuyi/_doc/1
{
  "name":"朱育仪",
  "age":24,
  "desc":"我明天就要分享了,我慌的一批",
  "tags":["技术宅","温暖","直男"]
}

PUT /yuyi/_doc/2
{
  "name":"张三",
  "age":24,
  "desc":"我是张三",
  "tags":["傻叉","旅游","渣男"]
}

PUT /yuyi/_doc/3
{
  "name":"李四",
  "age":30,
  "desc":"我是李四",
  "tags":["靓女","旅游","唱歌"]
}

2、查询 查询yuyi索引下的 1号人物

GET /yuyi/_doc/1

3、搜索 条件查询 获取一号用户的

GET /yuyi/_doc/_search?q=name:朱育仪

我们发现 上图中有一个 _score这个字段,如果有多条数据,匹配度越高则分值越高

略复杂的查询方式

GET /yuyi/_doc/_search
{
  "query":{
    "match":{
      "name":"朱育仪"
    }
  }
}

还是一样返回上文图片的返回值

通过 _source 指定返回值

GET /yuyi/_doc/_search
{
  "query":{
    "match":{
      "name":"朱育仪"
    }
  },
  "_source":["name","age"]
}

![]

我们之后使用nodejs 操作es,所有的方法和对象就是这里面的key!

排序

GET /yuyi/_doc/_search
{
  "query":{
    "match_all":{}
  },
  "sort":[
    {
      "age":{
        "order":"desc"
      }
    }
  ]
}

match_all代表全文匹配 sort 字段是个数组里面传递对象用来排序,上面的语句是对age进行排序,order代表排序规则“desc降序 asc升序” 有了固定的排序后,_score分值就没了。

分页

GET /yuyi/_doc/_search
{
  "query":{
    "match_all":{
    }
  },
  "sort":[
    {
      "age":{
        "order":"desc"
      }
    }
  ],
  "from":0,
  "size":2
}

from代表了从第几个开始,size表示每页多少个

布尔值查询

GET /yuyi/_doc/_search
{
  "query":{
    "bool":{
      "must":[
        {
          "match":{
            "name":"育仪"
          }
        },
        {
          "match":{
            "age":24
          }
        }
      ]
    }
  }
}

采用 bool字段, 内部可选参数:must(必须包含)must_not(必须不包含)should(有一个就可以了)(minimum_should_match: 用来控制至少匹配多少个should匹配的) 上面匹配的是 name包含 育仪字段 age24的数据

should查询测试

GET /yuyi/_doc/_search
{
  "query":{
    "bool":{
      "should":[
        {
          "match":{
            "name":"育仪"
          }
        },
        {
          "match":{
            "age":24
          }
        }
      ]
    }
  },
  "from":0,
  "size":2
}

会返回只要符合name 是育仪 或者 age是 24的就可以了。

过滤查询

GET /yuyi/_doc/_search
{
  "query":{
    "bool":{
      "must":[
        {
          "match":{
            "name":"育仪"
          }
        }
      ],
      "filter":{
        "range":{
          "age":{
            "gte":10,
            "lte":30
          }
        }
      }
    }
  }
}

通过 filter查询过滤数据,将过滤age大于等于10小于等于30的 gt大于 lt小于 gte大于等于 lte小于等于

数组类型也可以匹配

GET /yuyi/_doc/_search
{
  "query":{
    "match":{
      "tags":"男"
    }
  }
}

想要匹配多个条件直接空格隔开即可

GET /yuyi/_doc/_search
{
  "query":{
    "match":{
      "tags":"男 技术"
    }
  }
}

我们发现只要匹配到了这两个词中的任意一个,就会被返回,然而第二条数据并不太符合技术这个关键词。 这个时候可以通过返回值中的分值进行基本的判断,匹配程度。

精确查询

term 直接通过倒排索引精确查找的

关于分词,term会直接查询精确值,match会使用分词器解析,再通过分析的文档查询

两个类型 text keyword text类型会被分词器进行解析 keyword不会被分割解析

测试代码一个一个请求

PUT testdb
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "desc":{
        "type": "keyword"
      }
    }
  }
}

PUT testdb/_doc/1
{
  "name":"育仪准备分享会",
  "desc":"育仪准备分享会"
}

PUT testdb/_doc/2
{
  "name":"育仪准备分享会 name",
  "desc":"育仪准备分享会 desc"
}

查看分词结果

GET _analyze
{
  "analyzer": "keyword",
  "text":"育仪准备分享会"
}

如上图所示,keyword形式将不再进行分词

GET _analyze
{
  "analyzer": "ik_smart",
  "text":"育仪准备分享会"
}

使用ik分词器后是这个结果

精准查询的测试

GET /testdb/_search
{
  "query":{
    "term":{
      "name":"育"
    }
  }
}

查询name中含有的数据,由于name属性是text类型,会被分词

GET /testdb/_search
{
  "query":{
    "term":{
      "desc":"育"
    }
  }
}

此时我们发现 desc查询字时无值,由于我们使用了keyword类型 ,所以我们必须使用育仪准备分享会 全部文字才能匹配到值。如下方的测试

GET /testdb/_search
{
  "query":{
    "term":{
      "desc":"育仪准备分享会"
    }
  }
}

总结:keyword不会被分词器解析

多个值匹配的精确查询

测试代码(插入多个数据)

PUT testdb/_doc/3
{
  "t1":"22",
  "t2":"2020-09-23"
}
PUT testdb/_doc/4
{
  "t1":"33",
  "t2":"2020-09-24"
}

使用 term精确查询多个值

GET /testdb/_search
{
  "query":{
    "bool":{
      "should": [
        {
          "term":{
            "t1":"22"
          }
        },
        {
          "term":{
            "t1":"33"
          }
        }
      ]
    }
  }
}

高亮查询

GET /yuyi/_search
{
  "query":{
    "match":{
      "name":"育仪"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

通过 上文方式可以实现高亮,highlight``fields为固定写法

我们这里不想用em标签 想用其他的

GET /yuyi/_search
{
  "query":{
    "match":{
      "name":"育仪"
    }
  },
  "highlight": {
    "pre_tags": "<p class='myClassName' style='color:red'>", 
    "post_tags": "</p>", 
    "fields": {
      "name": {}
    }
  }
}

这里使用 pre_tags post_tags 来自定义标签高亮

参考文档:

Elasticsearch 集群分配多少分片合理

RESTful API接口设计标准及规范

Elasticsearch的停用词

Elasticsearch 之(24)IK分词器配置文件讲解以及自定义词库

ElasticSearch 9200和9300端口的作用

为什么现在要移除type?

Elasticsearch 入门学习

ik_max_word和 ik_smart介绍

还有很多借鉴其他的出处忘记了。。。