Loading

(一)、ElasticSearch简介

Elasticsearch简介

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。

*特点:*

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 分布式的实时分析搜索引擎--做不规则查询
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

ES能做什么?

全文检索(全部字段)、模糊查询(搜索)、数据分析(提供分析语法,例如聚合)

Elasticsearch使用案例

(1)2013年初,GitHub抛弃了Solr,采取ElasticSearch 来做PB级的搜索。 “GitHub使用ElasticSearch搜索20TB的数据,包括13亿文件和1300亿行代码”

(2)维基百科:启动以elasticsearch为基础的核心搜索架构SoundCloud:“SoundCloud使用ElasticSearch为1.8亿用户提供即时而精准的音乐搜索服务”

(3)百度:百度目前广泛使用ElasticSearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部20多个业务线(包括casio、云分析、网盟、预测、文库、直达号、钱包、风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据

(4)新浪使用ES 分析处理32亿条实时日志

(5)阿里使用ES 构建挖财自己的日志采集和分析体系

基本概念

Index(索引)

Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引

所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。

  • 动词,相当于mysql的insert
  • 名词,相当于mysql的database

es某个索引的某个类型下,就相当于mysql哪个数据库的哪个表下

Document(文档)

保存在某个 Index(索引)下,某种 Type(类型)的一个数据,Document(文档)是JSON格式的,Document 就像是 MySQL 中某个 Table 里面每一行的数据,字段就是Document里的属性。

在mysql中存的一条条叫数据,es中存的数据叫文档

Type(类型)

在 Index(索引)中,可以定义一个或多个类型。

类似于 MySQL 的 Table,每一种类 型的数据存放在一起。

在Elasticsearch6.0之后,Type 类型被移除。

image-20211001170919120

对比关系

索引(index)----------------------Databases 数据库

  类型(type)--------------------------Table 数据表

     文档(Document)----------------------Row 行

	    字段(Field)-------------------------Columns 列 

倒排索引

image-20211001170833734

Docker安装Elasticsearch、Kibana

Docker镜像网站:Docker Hub Container Image Library | App Containerization

1. 下载镜像文件

# 存储和检索数据
docker pull elasticsearch:7.4.2

# 可视化检索数据
docker pull kibana:7.4.2

image-20211001170807244

2.配置挂载数据文件夹

# 创建配置文件目录
mkdir -p /mydata/elasticsearch/config

# 创建数据目录
mkdir -p /mydata/elasticsearch/data

# 将/mydata/elasticsearch/文件夹中文件都可读可写
chmod -R 777 /mydata/elasticsearch/

# 配置任意机器可以访问 elasticsearch
echo "http.host: 0.0.0.0" >/mydata/elasticsearch/config/elasticsearch.yml

3. 启动Elasticsearch

docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e  "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v  /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2 

image-20211001172218661

  • -p 9200:9200 -p 9300:9300:向外暴露两个端口,9200用于HTTP REST API请求,9300 ES 在分布式集群状态下 ES 之间的通信端口;

  • -e "discovery.type=single-node":es 以单节点运行

  • -e ES_JAVA_OPTS="-Xms64m -Xmx512m":设置启动占用内存,不设置可能会占用当前系统所有内存

  • -v:挂载容器中的配置文件、数据文件、插件数据到本机的文件夹;

  • -d elasticsearch:7.6.2:指定要启动的镜像

4.安装成功

访问http://192.168.195.100:9200/ 显示以下内容则安装成功

image-20211001173740016

如果没有反应查看日志是否有error报错信息

docker logs elasticsearch

如果日志没有报错检查是否开启了虚拟机的防火墙,并开放相关9200端口才能显示成功

如果没有权限开启相关文件夹的读写操作权限

chmod -R 777 /mydata/elasticsearch/

5.启动可视化Kibana

-e ELASTICSEARCH_HOSTS=http://192.168.195.100:9200这里改成自己的虚拟机地址

docker run --name kibana \
-e ELASTICSEARCH_HOSTS=http://192.168.195.100:9200 \
-p 5601:5601 \
-d kibana:7.4.2

这里记得要添加防火墙端口

firewall-cmd --zone=public --add-port=5601/tcp --permanent 

查看开放的端口

sudo firewall-cmd --zone=public --list-ports

更新防火墙

sudo firewall-cmd --reload

image-20211001195219060

访问:Kibana

image-20211001195322347

6.配置启动方式

# 当前 Docker 开机自启,所以 kibana 现在也是开机自启
docker update kibana --restart=always

# 当前 Docker 开机自启,所以 ES 现在也是开机自启
docker update elasticsearch --restart=always

初步检索

_Cat

Elasticsearch 都是通过 REST API 接口来操作数据的,那么下面接通过几个接口的请求来演示它的使用

1.查看所有节点信息

http://192.168.195.100:9200/_cat/nodes

2.查看节点健康状况

http://192.168.195.100:9200/_cat/health

3.查看主节点信息

http://192.168.195.100:9200/_cat/master

4.查看所有索引

http://192.168.195.100:9200/_cat/indices

索引文档

即保存一条数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识

PUT 请求

http://192.168.195.100:9200/customer/external/1

image-20211001201435560

version:多次操作会更新版本

result:第一次是新增、第二次是更新

POST 请求

POST: http://192.168.195.100:9200/customer/external

image-20211001202104001

PUT和POST都可以

  • POST新增,如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本号;
  • PUT可以新增也可以修改。PUT必须指定id;由于PUT需要指定id,我们一般用来做修改操作,不指定id会报错。

查看文档

GET:http://192.168.195.100:9200/customer/external/1

image-20211001202217366

{
    "_index": "customer",  # 在哪个索引(库)
    "_type": "external",   # 在哪个类型(表)
    "_id": "1",						 # 文档id(记录)
    "_version": 5,				 # 版本号
    "_seq_no": 4,					 # 并发控制字段,每次更新都会+1,用来做乐观锁
    "_primary_term": 1,		 # 同上,主分片重新分配,如重启,就会变化
    "found": true,
    "_source": {					 # 数据
        "name": "zhangsan"
    }
}
# 乐观锁更新时携带 ?_seq_no=0&_primary_term=1  当携带数据与实际值不匹配时更新失败

更新文档

POST:http://192.168.195.100:9200/customer/external/1/_update

image-20211001203250064

result:noop表示更新数据跟原数据相同,没有做任何操作

更新文档的区别

POST、PUT请求带id都会直接更新数据,只有Post带(_update)才会检查更新

PUT请求带id更新和POST请求带id更新,会直接覆盖原来的数据,不会在原来的属性里面新增属性

删除索引

Delete:http://192.168.195.100:9200/customer/external/1

image-20211001204027474

查询不到数据了

image-20211001204052235

删除文档

Delete http://192.168.195.100:9200/custome/

bulk-批量操作数据

{action:{metadata}}\n   // 例如index保存记录,update更新
{request body  }\n

{action:{metadata}}\n
{request body  }\n

指定索引和类型的批量操作

接口:POST /customer/external/_bulk

参数:

{"index":{"_id":"1"}}
{"name":"John Doe"}
{"index":{"_id":"2"}}
{"name":"John Doe"}

在Kibana中使用dev-tools测试批量:

image-20211001210511561

对所有索引执行批量操作

接口:POST /_bulk

{"delete":{"_index":"website","_type":"blog","_id":"123"}}
{"create":{"_index":"website","_type":"blog","_id":"123"}}
{"title":"my first blog post"}
{"index":{"_index":"website","_type":"blog"}}
{"title":"my second blog post"}
{"update":{"_index":"website","_type":"blog","_id":"123"}}
{"doc":{"title":"my updated blog post"}}

image-20211001210924417

  • 这里的批量操作,当发生某一条执行发生失败时,其他的数据仍然能够接着执行,也就是说彼此之间是独立的。

  • bulk api以此按顺序执行所有的action(动作)。如果一个单个的动作因任何原因失败,它将继续处理它后面剩余的动作。

  • 当bulk api返回时,它将提供每个动作的状态(与发送的顺序相同),所以您可以检查是否一个指定的动作是否失败了。

批量导入测试数据

POST bank/account/_bulk

es测试数据.json · 坐看云起时/common_content - Gitee.com

image-20211001211717453

进阶检索

GET /bank/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "account_number": "asc"
    }
  ]
}
# query 查询条件
# sort 排序条件
Get bank/_search?q=*&sort=account_number:asc

image-20211001212947378

Elasticsearch 默认会分页返回10条数据,不会一下返回所有数据。

took—Elasticsearch运行查询所花费的时间,以毫秒为单位
timed_out-是否搜索请求超时
_shards -有多少碎片被搜索,有多少碎片成功,失败,或被跳过。
Max_score -找到的最相关文档的分数
Hits.total.value—找到了多少匹配的文档
hits.Sort—文档的排序位置(当不按相关性分数排序时)
hits._score -文档的相关分数(在使用match_all时不适用)

检索的两种方式

ES支持两种基本方式检索;

  • 通过REST request uri 发送搜索参数 (uri +检索参数);
  • 通过REST request body 来发送它们(uri+请求体);

还可以用GET请求参数的方式检索:

GET bank/_search?q=*&sort=account_number:asc
# q=* 查询所有
# sort=account_number:asc 按照account_number进行升序排列

Query DSL

Elasticsearch提供了一个可以执行查询的Json风格的DSL。这个被称为Query DSL,该查询语言非常全面

基本语法格式

一个查询语句的典型结构:

QUERY_NAME:{
   ARGUMENT:VALUE,
   ARGUMENT:VALUE,...
}

如果针对于某个字段,那么它的结构如下

{
  QUERY_NAME:{
     FIELD_NAME:{
       ARGUMENT:VALUE,
       ARGUMENT:VALUE,...
      }   
   }
}

请求示例:

GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "account_number": {
        "order": "desc"
      },
      "balance": {
        "order": "asc"
      }
    }
  ],
  "from": 0,
  "size": 5,
  "_source": ["balance","firstname"]
}
# match_all 查询类型【代表查询所有的所有】,es中可以在query中组合非常多的查询类型完成复杂查询;
# from+size 限定,完成分页功能;从第几条数据开始,每页有多少数据
# sort 排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序为准;
#_source 表示只显示哪一些字段,就像数据库的select xxx from

image-20211001214600563

match全文检索

精确查询-基本数据类型(非文本)

相当于sql语句的where=条件,查找account_number=20的数据

GET bank/_search
{
  "query": {
    "match": {
      "account_number": 20
    }
  }
}

模糊查询-文本字符串

GET bank/_search
{
  "query": {
    "match": {
      "address": "mill lane"
    }
  }
}
# 查找匹配 address 包含 mill 或 lane 的数据

match即全文检索,对检索字段进行分词匹配,会按照响应的评分 _score 排序,原理是倒排索引。

match_phrase 短语匹配

要想精确查找整个字符串,不使用分词,就需要用到match_phrase

GET bank/_search
{
  "query": {
    "match": {
      "address.keyword": "288 Mill Street"
    }
  }
}

image-20211001215323276

multi_math-多字段匹配

相当于sql多条件查询,检查多个字段中有包含xxx的数据,用到了分词

GET bank/_search
{
  "query": {
    "multi_match": {
      "query": "mill",
      "fields": [
        "city",
        "address"
      ]
    }
  }
}
# 检索 city 或 address 匹配包含 mill 的数据,会对查询条件分词

bool-复合查询

复合语句可以合并,任何其他查询语句,包括符合语句

  • must:必须达到must所列举的所有条件

  • must_not,必须不匹配must_not所列举的所有条件。

  • should,应该满足should所列举的条件。

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "gender": "M"
          }
        },
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "address": "111"
          }
        }
      ],
      "should": [
        {
          "match": {
            "address": "Lane"
          }
        }
      ]
    }
  }
}
# 查询 gender 为 M 且 address 包含 mill 的数据 
# 并且 address不等于111的数据
# 或者 address等于 Lane的数据

filter-结果过滤

并不是所有的查询都需要产生分数,特别是哪些仅用于filtering过滤的文档。为了不计算分数,elasticsearch会自动检查场景并且优化查询的执行。

filter 对结果进行过滤,且不计算相关性得分。

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "filter": {
        "range": {
          "balance": {
            "gte": "10000",
            "lte": "20000"
          }
        }
      }
    }
  }
}
# 这里先是查询所有匹配 address 包含 mill 的文档,
# 然后再根据 10000<=balance<=20000 进行过滤查询结果 匹配到也不会增加分数,单纯查找作用

term-精确检索

对于非文本字段,使用 term来精确检索是一个推荐的选择,如果要查询文本字段值,请使用 match 查询代替。

GET bank/_search
{
  "query": {
    "term": {
      "age": "28"
    }
  }
}
# 查找 age 为 28 的数据

Aggregation-执行聚合

https://www.elastic.co/guide/en/elasticsearch/reference/7.11/search-aggregations.html

聚合语法

GET /my-index-000001/_search
{
  "aggs":{
    "aggs_name":{ # 这次聚合的名字,方便展示在结果集中
        "AGG_TYPE":{ # 聚合的类型(avg,term,terms)
        } 
     }
  }
}

搜索address中包含mill的所有人的年龄分布以及平均年龄

聚合字段为 age,聚合后前十个数据,求聚合字段为 age的平均值,求聚合字段为 balance的平均值

对address=mill的年龄进行分组,然后求这些组里面age和balance的平均值

GET bank/_search
{
  "query": {
    "match": {
      "address": "Mill"
    }
  },
  "aggs": {
    "ageAgg": {
      "terms": {
        "field": "age",
        "size": 10
      }
    },
    "ageAvg": {
      "avg": {
        "field": "age"
      }
    },
    "balanceAvg": {
      "avg": {
        "field": "balance"
      }
    }
  },
  "size": 0
}

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "ageAgg" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 38,
          "doc_count" : 2
        },
        {
          "key" : 28,
          "doc_count" : 1
        },
        {
          "key" : 32,
          "doc_count" : 1
        }
      ]
    },
    "ageAvg" : {
      "value" : 34.0
    },
    "balanceAvg" : {
      "value" : 25208.0
    }
  }
}

按照年龄聚合,并且求这些年龄段的这些人的平均薪资

GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAgg": {
      "terms": {
        "field": "age",
        "size": 100
      },
      "aggs": {
        "ageAvg": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 0
}

image-20211001223551777

查出所有年龄分布,并且这些年龄段中M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资

根据年龄分组,再根据男女性别分组,再根据性别分别求平均薪资。求分组年龄的平均薪资

GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAgg": {
      "terms": {
        "field": "age",
        "size": 100
      },
      "aggs": {
        "genderAgg": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "balanceAvg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        },
        "ageBalanceAvg": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 0
}
# "field": "gender.keyword" gender是txt没法聚合 必须加.keyword精确替代

Mapping-映射

默认添加数据就会找到相应的字段类型

Maping是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。

比如:使用maping来定义:

  • 哪些字符串属性应该被看做全文本属性(full text fields);

  • 哪些属性包含数字,日期或地理位置;

  • 文档中的所有属性是否都嫩被索引(all 配置);

  • 日期的格式;

  • 自定义映射规则来执行动态添加属性;

查看mapping信息

GET bank/_mapping

{
  "bank" : {
    "mappings" : {
      "properties" : {
        "account_number" : {
          "type" : "long"
        },
        "address" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "balance" : {
          "type" : "long"
        },
        "city" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "email" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "employer" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "firstname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "gender" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "lastname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "state" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

新版本type移除

ElasticSearch7-去掉type概念

  1. 关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的。
    • 两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。
    • 去掉type就是为了提高ES处理数据的效率。
  1. Elasticsearch 7.x URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型。

  2. Elasticsearch 8.x 不再支持URL中的type参数。

  3. 解决:
    将索引从多类型迁移到单类型,每种类型文档一个独立索引
    将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移

属性类型

参考:官方属性类型

映射操作

参考:创建映射操作

创建索引映射

PUT /my_index
{
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "email": {
        "type": "keyword"
      },
      "name": {
        "type": "text"
      }
    }
  }
}

结果

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "my_index"
}

给已有映射增加字段

https://www.elastic.co/guide/en/elasticsearch/reference/7.x/explicit-mapping.html#add-field-mapping

PUT /my_index/_mapping
{
  "properties": {
    "employee-id": {
      "type": "keyword",
      "index": false
    }
  }
}

# 这里的 "index": false,表明新增的字段不能被检索。默认是true
# https://www.elastic.co/guide/en/elasticsearch/reference/7.x/mapping-index.html

更新映射

https://www.elastic.co/guide/en/elasticsearch/reference/7.x/explicit-mapping.html#update-mapping

对于已经存在的字段映射,我们不能更新。更新必须创建新的索引,进行数据迁移

迁移方式分为两种,一种是7和7之后去掉type的情况,一种是包含type 迁移的情况

无type数据迁移

POST reindex [固定写法]
{
  "source":{
      "index":"twitter"
   },
  "dest":{
      "index":"new_twitters"
   }
}

有type数据迁移

POST reindex [固定写法]
{
  "source":{
      "index":"twitter",
      "twitter":"twitter"
   },
  "dest":{
      "index":"new_twitters"
   }
}

数据迁移实例

对于我们的测试数据,是包含 type 的索引 bank。

现在我们创建新的索引 newbank 并修改一些字段的类型来演示当需要更新映射时的数据迁移操作。

当前数据类型

GET /bank/_mapping

创建新索引,修改字段类型

PUT /newbank
{
  "mappings": {
    "properties": {
      "account_number": {
        "type": "long"
      },
      "address": {
        "type": "text"
      },
      "age": {
        "type": "integer"
      },
      "balance": {
        "type": "long"
      },
      "city": {
        "type": "keyword"
      },
      "email": {
        "type": "keyword"
      },
      "employer": {
        "type": "keyword"
      },
      "firstname": {
        "type": "text"
      },
      "gender": {
        "type": "keyword"
      },
      "lastname": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "state": {
        "type": "keyword"
      }
    }
  }
}

数据迁移

POST _reindex
{
  "source": {
    "index": "bank",
    "type": "account"
  },
  "dest": {
    "index": "newbank"
  }
}

迁移后 type 统一为 _doc 移除 type

image-20211001230455045

ElasticSearch分词

一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流。

例如:whitespace tokenizer遇到空白字符时分割文本。它会将文本“Quick brown fox!”分割为[Quick,brown,fox!]。

该tokenizer(分词器)还负责记录各个terms(词条)的顺序或position位置(用于phrase短语和word proximity词近邻查询),以及term(词条)所代表的原始word(单词)的start(起始)和end(结束)的character offsets(字符串偏移量)(用于高亮显示搜索的内容)。

elasticsearch提供了很多内置的分词器,可以用来构建custom analyzers(自定义分词器)。

POST _analyze
{
  "analyzer": "standard",
  "text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}

默认的分词器一般都是针对于英文,对于中文我们需要安装额外的分词器来进行分词。

安装IK分词器

IK属于Elasticsearch 的插件,所以 IK 分词器的安装目录是 Elasticsearch 的 plugins 目录

  • 在我们使用Docker启动 Elasticsearch 时,已经将该目录挂载到主机的 /mydata/elasticsearch/plugins 目录。
  • IK 分词器的版本需要跟 Elasticsearch 的版本对应,当前选择的版本为 7.4.2,下载地址为:Github Release 或访问:镜像地址
# 进入挂载的插件目录 /mydata/elasticsearch/plugins
cd /mydata/elasticsearch/plugins

# 安装 wget 下载工具
 yum install -y wget

# 下载对应版本的 IK 分词器(这里是7.4.2)
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip

所以我们之后只需要在挂载的目录/mydata/elasticsearch/plugins下进行操作即可。

解压

# 进入到 es 的插件目录
cd /mydata/elasticsearch/plugins

# 解压到 plugins 目录下的 ik 目录
unzip elasticsearch-analysis-ik-7.4.2.zip -d ik

# 删除下载的压缩包
 rm -f elasticsearch-analysis-ik-7.4.2.zip 

# 修改文件夹访问权限
chmod -R 777 ik/

查看安装的ik插件

# 进入 es 容器内部
docker exec -it elasticsearch /bin/bash

# 进入 es bin 目录
cd /usr/share/elasticsearch/bin

# 执行查看命令  显示 ik
elasticsearch-plugin list

# 退出容器
exit

# 重启 Elasticsearch
docker restart elasticsearch

测试 ik 分词器

GET my_index/_analyze
{
   "analyzer": "ik_max_word", 
   "text":"我是湖南岳阳人"
}

image-20211002092429360

这里对于默认词库中没有的词,不会有词语的组合,所以我们可以通过配置自定义词库或远程词库来实现对词库的扩展

自定义分词库

我们在 nginx 中自定义分词文件,通过配置 es 的 ik 配置文件来远程调用 nginx 中的分词文件来实现自定义扩展词库

docker安装nginx

1.创建要挂载的配置目录

mkdir -p /mydata/nginx/conf

2.启动临时nginx容器

docker run -p 80:80 --name nginx -d nginx:1.10
  1. 拷贝出 Nginx 容器的配置
# 将nginx容器中的nginx目录复制到本机的/mydata/nginx/conf目录
docker container cp nginx:/etc/nginx /mydata/nginx/conf

# 复制的是nginx目录,将该目录的所有文件移动到 conf 目录
mv /mydata/nginx/conf/nginx/* /mydata/nginx/conf/

# 删除多余的 /mydata/nginx/conf/nginx目录
rm -rf /mydata/nginx/conf/nginx
  1. 删除临时nginx容器
# 停止运行 nginx 容器
docker stop nginx

# 删除 nginx 容器
docker rm nginx

5.启动 nginx 容器

docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf/:/etc/nginx \
-d nginx:1.10

6.nginx 随 Docker 启动

docker update nginx --restart=always

7.测试 nginx

echo '<h1>谷粒商城源码</h1>' \
>/mydata/nginx/html/index.html

访问:192.168.195.100

nginx 中自定义分词文件

vim /mydata/nginx/html/fenci.txt

image-20211002095842712

给 es 配置自定义词库

# 1. 打开并编辑 ik 插件配置文件
vim /mydata/elasticsearch/plugins/ik/config/IKAnalyzer.cfg.xml

修改内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict"></entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <entry key="remote_ext_dict">http://192.168.195.100/fenci.txt</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

重启 elasticsearch 容器

docker restart elasticsearch

测试自定义词库

GET my_index/_analyze
{
   "analyzer": "ik_max_word", 
   "text":"我是湖南岳阳人"
}

image-20211002100227466

posted @ 2021-10-12 16:54  炒焖煎糖板栗  阅读(338)  评论(0编辑  收藏  举报