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 类型被移除。
对比关系
索引(index)----------------------Databases 数据库 类型(type)--------------------------Table 数据表 文档(Document)----------------------Row 行 字段(Field)-------------------------Columns 列
倒排索引
Docker安装Elasticsearch、Kibana
Docker镜像网站:Docker Hub Container Image Library | App Containerization
1. 下载镜像文件
# 存储和检索数据 docker pull elasticsearch:7.4.2 # 可视化检索数据 docker pull kibana:7.4.2
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
-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/ 显示以下内容则安装成功
如果没有反应查看日志是否有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
访问:Kibana
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
version:多次操作会更新版本
result:第一次是新增、第二次是更新
POST 请求
POST: http://192.168.195.100:9200/customer/external
PUT和POST都可以
- POST新增,如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本号;
- PUT可以新增也可以修改。PUT必须指定id;由于PUT需要指定id,我们一般用来做修改操作,不指定id会报错。
查看文档
GET:http://192.168.195.100:9200/customer/external/1
{ "_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
result:noop表示更新数据跟原数据相同,没有做任何操作
更新文档的区别
POST、PUT请求带id都会直接更新数据,只有Post带(_update)才会检查更新
PUT请求带id更新和POST请求带id更新,会直接覆盖原来的数据,不会在原来的属性里面新增属性
删除索引
Delete:http://192.168.195.100:9200/customer/external/1
查询不到数据了
删除文档
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测试批量:
对所有索引执行批量操作
接口: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"}}
- 这里的批量操作,当发生某一条执行发生失败时,其他的数据仍然能够接着执行,也就是说彼此之间是独立的。
- bulk api以此按顺序执行所有的action(动作)。如果一个单个的动作因任何原因失败,它将继续处理它后面剩余的动作。
- 当bulk api返回时,它将提供每个动作的状态(与发送的顺序相同),所以您可以检查是否一个指定的动作是否失败了。
批量导入测试数据
POST bank/account/_bulk
es测试数据.json · 坐看云起时/common_content - Gitee.com
进阶检索
GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ] } # query 查询条件 # sort 排序条件
Get bank/_search?q=*&sort=account_number:asc
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
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" } } }
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 }
查出所有年龄分布,并且这些年龄段中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概念
- 关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的。
- 两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。
- 去掉type就是为了提高ES处理数据的效率。
- Elasticsearch 7.x URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型。
- Elasticsearch 8.x 不再支持URL中的type参数。
- 解决:
将索引从多类型迁移到单类型,每种类型文档一个独立索引
将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移
属性类型
参考:官方属性类型
映射操作
参考:创建映射操作
创建索引映射
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.htmladd-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.htmlupdate-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
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":"我是湖南岳阳人" }
这里对于默认词库中没有的词,不会有词语的组合,所以我们可以通过配置自定义词库或远程词库来实现对词库的扩展。
自定义分词库
我们在 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
- 拷贝出 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
- 删除临时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
nginx 中自定义分词文件
vim /mydata/nginx/html/fenci.txt
给 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":"我是湖南岳阳人" }