一、检索概述

应用经常需要添加检索功能,开源的 ElasticSearch 是目前全文搜索引擎的首选。他可以快速的存储、搜索和分析海量数据。Spring Boot通过整合Spring Data ElasticSearch为我们提供了非常便捷的检索功能支持;
Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard(分片)的方式保证数据安全,并且提供自动resharding的功能,github等大型的站点也是采用了ElasticSearch作为其搜索服务。
官方文档

二 、使用docker安装Elasticsearch

docker pull elasticsearch:7.4.2 下载镜像
docker pull kibana:7.4.2 下载kibana可视化 界面
docker images 查看下载好了哪些镜像
docker ps 查看正在运行的服务
free -m 查看虚拟机可用内存

mkdir -p /mydata/elasticsearch/config --创建目录
mkdir -p /mydata/elasticsearch/data --创建目录
echo “http.host: 0.0.0.0” >> /mydata/elasticsearch/config/elasticsearch.yml --在elasticsearch.yml中配置在任何ip地址可以访问es服务,这里的冒号后面有一个空格

chmod -R 777 /mydata/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

使用9200端口访问返回json数据说明成功

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch

注:此处请关闭防火墙(关闭后重启docker)systemctl stop firewalld

查看防火墙状态systemctl status firewalld

安装kibana可视化界面

docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.20.66:9200 -p 5601:5601

-d kibana:7.4.2

稍等kibana彻底启动后访问5601端口:看到以下界面代表成功

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_02


配置elasticsearch和kibana开机启动

docker update 容器id --restart=always

注意Elasticsearch版本应该与springboot版本匹配
版本适配说明:版本适配说明 应安装Spring Data 对应版本的ElasticSearch
默认的ElasticSearch的web端口为9200
分布式节点之间通信使用的接口为9300
使用ElasticSearch会占用2G的内存空间为防止内存溢出所以这里设置其大小。

此处记一坑

通过docker命令开启elasticsearch7.5访问9200被拒绝elasticsearch7.5服务会自动关闭,可通过docker logs -f 容器id查看日志日志显示

Fragment 获取 smartRefreshLayout findViewById报错_数据_03


解决方法:

查看虚拟机是否安装jdk:

执行liunx命令:

vi /etc/sysctl.conf

在文件末尾添加:

vm.max_map_count=262144

执行liunx命令,立即执行

/sbin/sysctl -p

启动再次秒退查看容器日志

Fragment 获取 smartRefreshLayout findViewById报错_字段_04


降低elasticsearch版本为6.5.0访问9200端口成功

三、Elasticsearch中的几个概念

倒排索引:将我们要存储的一个短语进行分词处理得到多个分词,并将索引的位置存放到各个分词中;

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_05


与数据库类比

  • 索引-数据库
  • 类型-表 这里的类型概念在elasticsearch7.0之后被删除不再使用,在下面的第五-》4.mapping映射 中会说明 原因
  • 文档-表中的记录
  • 属性-列

3.1 核心概念

3.1.1 索引(Index)

一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。
能搜索的数据必须索引,这样的好处是可以提高查询速度,比如:新华字典前面的目录就是索引的意思,目录可以提高查询速度。
Elasticsearch索引的精髓:一切设计都是为了提高搜索的性能。

3.1.2 类型(Type)

在一个索引中,你可以定义一种或多种类型。
一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。不同的版本,类型发生了不同的变化
版本 Type:5.x支持多种type 6.x 只能有一种type 7.x 默认不再支持自定义索引类型(默认类型为:_doc)

3.1.3 文档(Document)

一个文档是一个可被索引的基础信息单元,也就是一条数据
比如:你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,你可以存储任意多的文档。

3.1.4 字段(Field)

相当于是数据表的字段,对文档数据根据不同属性进行的分类标识。

3.1.5 映射(Mapping)

mapping是处理数据的方式和规则方面做一些限制,如:某个字段的数据类型、默认值、分析器、是否被索引等等。这些都是映射里面可以设置的,其它就是处理ES里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。

3.1.6 分片(Shards)

一个索引可以存储超出单个节点硬件限制的大量数据。比如,一个具有10亿文档数据的索引占据1TB的磁盘空间,而任一节点都可能没有这样大的磁盘空间。或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,每一份就称之为分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片很重要,主要有两方面的原因:

  • 允许你水平分割 / 扩展你的内容容量。
  • 允许你在分片之上进行分布式的、并行的操作,进而提高性能/吞吐量。
    至于一个分片怎样分布,它的文档怎样聚合和搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,无需过分关心。
    被混淆的概念是,一个 Lucene 索引我们在 Elasticsearch 称作 分片 。 一个Elasticsearch 索引是分片的集合。 当 Elasticsearch 在索引中搜索的时候, 他发送查询到每一个属于索引的分片(Lucene 索引),然后合并每个分片的结果到一个全局的结果集。

3.1.7 副本(Replicas)

在一个网络 / 云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片(副本)。
复制分片之所以重要,有两个主要原因:

  • 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
  • 扩展你的搜索量/吞吐量,因为搜索可以在所有的副本上并行运行。
    总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。默认情况下,Elasticsearch中的每个索引被分片1个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有1个主分片和另外1个复制分片(1个完全拷贝),这样的话每个索引总共就有2个分片,我们需要根据索引需要确定分片个数。

3.1.8 分配(Allocation)

将分片分配给某个节点的过程,包括分配主分片或者副本。如果是副本,还包含从主分片复制数据的过程。这个过程是由master节点完成的。

3.2 系统架构

Fragment 获取 smartRefreshLayout findViewById报错_字段_06


一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。

当一个节点被选举成为主节点时, 它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。 任何节点都可以成为主节点。我们的示例集群就只有一个节点,所以它同时也成为了主节点。

作为用户,我们可以将请求发送到集群中的任何节点 ,包括主节点。 每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。 无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回給客户端。 Elasticsearch 对这一切的管理都是透明的。

测试Elasticsearch的几个常用操作
这里为了方便使用postman模拟web应用发送的请求

  • 索引一个员工文档
  • Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_07

  • _index:索引名
    _type:文档类型
    _id:文档id
    _version:版本号
    _source:文档内容
  • 检索操作
  1. 检索员工文档中id为1的文档
    GET http://192.168.1.5:9200/megacorp/employee/1
  2. 检索所有员工文档
    GET http://192.168.1.5:9200/megacorp/employee/_search
  3. 检索员工文档中姓氏为Smith的
    GET http://192.168.1.5:9200/megacorp/employee/_search?q=last_name:Smith
  4. 使用查询表达式搜索姓氏为Smith的
  • 删除索引中文档id为3的员工文档

    更多操作参考:使用文档

四、初步检索

1._cat查询es的信息

GET/_cat/nodes 查看所有节点—>集群中每个es都是一个节点
GET/_cat/health 查看es健康状况
GET/_cat/master 查看主节点–>集群中的主节点
GET/_cat/indices 查看所有索引–>相当于show databases

2.索引一个文档(保存)PUT/POST

PUT或POST/megacorp/employee/1---------携带的数据使用json类型
post:新增时可以不携带id,自动生成id;若携带id但该id之前已经存在数据就会执行覆盖操作并修改版本号,若不存在则会新增数据
put :必须携带id唯一标识进行保存操作,若id已存在就执行修改并修改版本号,若不存在执行新增

我们在索引一个对象数组时es会将我们的数组进行扁平化

Fragment 获取 smartRefreshLayout findViewById报错_数据_08


使用嵌入式属性解决扁平化处理导致的错误,需要在创建索引时为属性指定type为nested

Fragment 获取 smartRefreshLayout findViewById报错_字段_09

3.查询文档GET

GET /megacorp/employee/1
_index:在哪个索引名
_type:在哪个文档类型
_id:文档id
_version:版本号
_seq_no:序列号,并发控制字段,每次更新就会+1,用来做乐观锁
_primary_term:主分片重新分配,如重启会变化
_source:真正的内容

4.更新文档

POST/megacorp/employee/_update 携带的数据使用json类型使用{“doc”:{属性名:属性值}}包裹携带的数据
更新操作会对比原数据,若数据无改变,版本号与序列号就不会发生变化
若在请求时不携带_update就不会对比数据,无论数据是否与原数据相同,版本号与序列号都会发生变化
PUT方式无论是否携带_update都不会对比原数据,直接更新数据

5.删除文档

DELETE /megacorp/employee/1
只提供删除索引与删除指定文档不能删除某个类型

6.bulk批量API

POST /megacorp/employee/_bulk 为某个索引的某个类型批量增加索引
请求体:raw–>josn
{“index”:{"_id":2}}
{“name”:“zhangsan”}
{“index”:{"_id":3}}
{“name”:“lisi”}
批量操作都是单个操作的这里区别于mysql的事务,即使有一个失败了别的也会正常运行

五、进阶检索

准备数据:https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/accounts.json

将数据索引到bank/account下

POST /bank/account/_bulk 请求体为网址中的josn数据

Fragment 获取 smartRefreshLayout findViewById报错_数据_10


官方文档

es支持两种基本检索方式:

1.SearchAPI检索信息–发送搜索参数(uri+检索参数)

GET bank/_search?q=*&sort=account_number:asc 检索bank索引下的所有文档并根据账号升序排列

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_11

took :Elasticsearch运行查询多长时间(以毫秒为单位)
timed_out :搜索请求是否超时
_shards :搜索了多少个分片,以及成功,失败或跳过了多少个分片。
max_score :找到的最相关文件的分数
hits.total.value:找到了多少个匹配的文档
hits.sort :文档的排序位置(不按相关性得分排序时)
hits._score:文档的相关性得分(使用时不适用match_all)
hits._source:文档的内容

2.Query DSL(uri+请求体)

查询表达式(Query DSL)是一种非常灵活又富有表现力的 查询语言。 Elasticsearch 使用它可以以简单的 JSON 接口来展现 Lucene 功能的绝大部分

基本语法

GET bank/_search

{
    "query": {			//查询条件
        "match": {		//匹配tweet字段包含elasticsearch的数据		match-all是匹配所有数据
            "tweet": "elasticsearch"
        }
    },
    "sort":[{				//排序条件先按照balance字段排序,再根据account_number排序
     		"balance":{	//,指定order规则,为降序
     				"order":"desc"
     		},
     		{ 
     		"account_number": "asc" 
     		}
     }],
     "from":0,	//从第一条开始
     "size":5,	//每次取5条数据
     "_source":[{"balance","firstname"}]		//只返回文档中的balance与firstname字段
}

使用 match 查询语句 来查询 tweet 字段中包含 elasticsearch 的 tweet:
查询所有 match_all 查询简单的匹配所有文档。在没有指定查询方式时,它是默认的查询:
全文检索 match 若匹配的字段值为数字则进行的是精确检索(即相等的才会被查出来),
若匹配的是非数字会对检索条件进行分词匹配,只要包含分词的都会被查出,并按照评分(指定字符串的匹配程度)进行排序。
短语匹配 match_phrase 将查询条件当作一个不可分割的短语去查询,
多字段匹配 multi_match 查询可以在多个字段上执行相同的 match 查询(会进行多个字段的全文检索)

{
    "multi_match": {
        "query":    "full text search",
        "fields":   [ "title", "body" ]
    }
}

复合查询 bool你可以用 bool 查询来实现你的需求。这种查询将多查询组合在一起,成为用户自己想要的布尔查询。
它接收以下参数:
must:文档必须匹配这些条件才能被包含进来。匹配到增加得分
must_not:文档必须不匹配这些条件才能被包含进来。不影响得分
should:最好满足,如果满足这些语句中的任意语句,将增加 _score得分,不满足也无任何影响。
filter:必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。

GET /_search
{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }},
            { "range": { "date": { "gte": "2014-01-01" }}}
        ]
    }
}

增加带过滤器 filter 若不想因为文档的时间而影响得分,可以用 filter 语句来重写
如果你需要通过多个不同的标准来过滤你的文档,bool 查询本身也可以被用做不评分的查询。简单地将它放置到 filter 语句中并在内部构建布尔逻辑:

GET /_search
{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }}
        ],
        "filter": {
          "bool": { 
              "must": [
                  { "range": { "date": { "gte": "2014-01-01" }}},
                  { "range": { "price": { "lte": 29.99 }}}
              ],
              "must_not": [
                  { "term": { "category": "ebooks" }}
              ]
          }
        }
    }
}

精确查询 term 查询被用于精确值匹配,这些精确值可能是数字、时间、布尔或者那些 not_analyzed(不分词)的字符串
全文检索用match,其他非text字段匹配用term.若想使用match精确匹配可以在匹配时为字段加上keyword
例:“balance.keyword”

GET /_search
{
    "query": {
        "term": {
            "user": {
                "value": "Kimchy",
                "boost": 1.0
            }
        }
    }
}

range 查询
range 查询找出那些落在指定区间内的数字或者时间:

{
    "range": {
        "age": {
            "gte":  20,
            "lt":   30
        }
    }
}

gt大于;gte大于等于;lt小于;lte小于等于

exists 查询和 missing 查询
exists 查询和 missing 查询被用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档。这与SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 在本质上具有共性:

{
    "exists":   {
        "field":    "title"
    }
}

这些查询经常用于某个字段有值的情况和某个字段缺值的情况。

3.aggregations聚合

聚合可以让我们极其方便的实现对数据的统计、分析。例如:
什么品牌的手机最受欢迎?
这些手机的平均价格、最高价格、最低价格?
这些手机每月的销售情况如何?
实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现实时搜索效果。

聚合有四个关键字:Metric(指标)、Bucketing(桶)、Matrix(矩阵)、Pipeline(管道),在查询请求体中以aggregations语法来定义聚合分析,也可简写成aggs

  • Metric(指标):指标分析类型,如计算最大值、最小值、平均值等(对桶内的文档进行聚合分析的操作)
  • Bucket(桶):分桶类型,类似sql中的group by语法(满足特定条件的文档的集合)
  • Pipeline(管道):管道分析类型,基于上一级的聚合分析结果进行再分析
  • Matrix(矩阵):矩阵分析类型(聚合是一种面向数值型的聚合,用于计算一组文档字段中的统计信息)
##搜索address中包含mill的所有人的年龄分布以及平均年龄
GET bank/_search
{
  "query": {
    "match": {
      "address": "mill"
    }
  },
  "aggs": {
    "ageAggs": {
      "terms": {	//查询年龄分布信息
        "field": "age",
        "size": 100
      }
    },
    "aggsAvg": {
      "avg": {
        "field": "age"
      }
    }
  }
}

##按照年龄聚合,并且求这些年龄段的这些人的平均薪资
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAgg": {
      "terms": {
        "field": "age",
        "size": 100
      },
      "aggs": {
        "ageAvgBalance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

##查出所有年龄分布,并且求这些年龄段中男性的平均薪资和女性的平均薪资以及这个年龄段的总体平均薪资
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAggs": {
      "terms": {
        "field": "age",
        "size": 100
      },
      "aggs": {
        "genderAggs": {
          "terms": {
            "field": "gender.keyword",
            "size": 10
          },
          "aggs": {
            "balanceAvg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        },
        "ageBalanceAvg":{
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

可在聚合每内部进行对聚合结果进行子聚合,语法与聚合相同

4.Mapping(映射)

Mapping是ES中的一个很重要的内容,它类似于传统关系型数据中table的schema,用于定义一个索引(index)中的类型(type)的数据的结构。 在ES中,我们可以手动创建type(相当于table)和mapping(相关与schema),也可以采用默认创建方式。在默认配置下,ES可以根据插入的数据自动地创建type及其mapping。 mapping中主要包括字段名、字段数据类型和字段索引类型

为什么类型概念被移除了?

上面,我们说索引和关系数据库的库是对等的的,类型和表是对等的。
这个观点其实是不正确的,在关系型数据库里,表是相互独立的,两个不同表里的同名列没有关系,互不影响。

但在索引里,所有类型的相同字段内部使用的是同一个lucene字段存储。上例中,user类型和tweet类型的user_name是存储在一个字段里的,但这是有问题的,例如你希望同一个索引中deleted字段在一个类型里是存储日期值,在另外一个类型里存储布尔值。而且索引中,存储仅有小部分字段相同或者全部字段都不相同的文档,会导致数据稀疏,影响Lucene有效压缩数据的能力。

字段类型

Elasticsearch 支持如下简单域类型:
字符串: string
整数 : byte, short, integer, long
浮点数: float, double
布尔型: boolean
日期: date
当你索引一个包含新域的文档Elasticsearch 会使用动态映射 ,通过JSON中基本数据类型,尝试猜测域类型,使用如下规则:

布尔型: true 或者 false—>boolean
整数: 123—>long
浮点数: 123.45—>double
字符串、有效日期: 2014-09-15—>date
字符串: foo bar—>string

如果通过引号( “123” )索引一个数字,它会被映射为 string 类型,而不是 long 。但是,如果我们设置了映射为 long ,那么 Elasticsearch 会尝试将这个字符串转化为 long ,如果无法转化,则抛出一个异常。

定义映射

## 保存索引并创建映射规则
PUT /my_index
{
  "mappings": {
    "properties": {
      "age":{ "type": "integer"},
      "email":{ "type": "keyword"},
      "name":{ "type": "text"}     
    }
  }

为索引 gb 中类型 (tweet) 创建映射规则 7.0之后类型概念被移除

GET /gb/_mapping/tweet
{
   "gb": {
      "mappings": {
         "tweet": {
            "properties": {
               "date": {
                  "type": "date",
                  "format": "strict_date_optional_time||epoch_millis"
               },
               "name": { "type": "string"},
               "tweet": {"type": "string"},
               "user_id": {"type": "long"},
               "add_file":{				//为索引中添加新的字段设置映射时应使用index
               		"type": "long",
               		"index":false
               }
            }
         }
      }
   }
}

为原有的映射添加新的字段使用 /索引名/_mapping

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

更新字段的映射

可以给一个存在的映射添加新的字段类型映射,但不能修改存在的字段类型映射。如果一个字段类型映射已经存在,那么该字段类型映射可能已经被索引。如果你意图修改这个字段类型映射,索引的数据可能会出错,不能被正常的搜索。(使用数据迁移解决)

数据迁移

GET bank/_mapping 查看原有索引的映射
根据原有索引映射,创建一个新的索引newbank书写正确的属性类型映射

PUT /newbank
{
  "mappings": {
    "properties": {
      "account_number": {"type": "long"},
      "address": {"type": "text"},
      "age": {"type": "integer"},
      "balance": {"type": "long"},
      "city": {"type": "text"},
      "email": {"type": "keyword"},	//对email字段进行精确检索设置
      "employer": {"type": "keyword"},
      "firstname": {"type": "text"},
      "gender": {"type": "keyword"},
      "lastname": {		//对lastname字段进行精确检索和分词匹配
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "state": {"type": "keyword"}
    }
  }
}

若es版本小于7.0在数据迁移时需要在source属性中加上type字段指定相应的类型即可

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

六、ik分词器

es自带的分词器全是基于英文的这里我们要安装可以处理中文的分词器

分词器安装

下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases 下载与es版本对应的ik分词器(不要点击tag去选版本下载来的文件少东西)

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_12

前面安装es时我们讲文件挂载到了mydata下 这里下载解压可以直接将文件夹使用xftp拷贝到服务器上

也可以使用下面的wget命令安装ik分词器

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_13


安装完成需要使用命令修改ik的读写权限

chmod -R 777 ik/

检查是否安装成功
安装后重启容器
docker restart elasticsearch
检查分词器是否安装成功
docker exec -it 容器id /bin/bash 进入es的控制台
elasticsearch-plugin list 查看所有已经安装的插件
尝试使用ik分词器进行分词(发现乔碧萝新词不能像预期的那样分成一个次这是我们就需要扩展自定义词库)

POST _analyze
{
  "analyzer": "ik_max_word",
  "text":"一群嘴炮!"
}

Fragment 获取 smartRefreshLayout findViewById报错_数据_14

自定义扩展词库

场景:ik分词器默认不能识别流行新词,这是就需要自定义扩展词库
解决方法:
指定远程词库向远程词库获取新的分词库,使用新的分词库进行分解单词
**将最新词库放入nginx让ik分词器给nginx发送请求,nginx给我们返回最新的词库 **

先安装nginx 参考nginx基于docker环境搭建 在安装好的nginx环境下的html文件夹下新建es文件夹与fenci.txt文件 这就是我们扩展的自定义词库

mkdir es
vi fenci.txt

修改/mydata/elasticsearch/plugins/ik/config配置文件

vi /mydata/elasticsearch/plugins/ik/config IKAnalyzer.cfg.xml

修改前的文件

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_15


修改后的文件

Fragment 获取 smartRefreshLayout findViewById报错_数据_16


这里远程扩展字典的词库文件fenci.txt存在我们的nginx中,以后若想添加分词则在fenci.txt中加入即可

将嘴炮添加到分词中再次进行分词

POST _analyze
{
  "analyzer": "ik_smart",
  "text":"一群嘴炮!"
}

Fragment 获取 smartRefreshLayout findViewById报错_字段_17

七、整合ElasticSearch测试

SpringBoot默认支持两种技术来和ES交互

  • Jest(默认不生效)
    需要导入jest的工具包依赖(io.searchbox.client.JestClient)
<!-- jestClient方式操作elasticsearch -->
        <dependency>
            <groupId>io.searchbox</groupId>
            <artifactId>jest</artifactId>
            <version>6.3.1</version>
        </dependency>

boot配置文件

spring.elasticsearch.jest.uris=http://192.168.1.5:9200

测试使用jest

@SpringBootTest
class BootSenior03ElasticsearchApplicationTests {

    @Autowired
    JestClient jestClient;

    @Test
    void contextLoads() throws IOException {
        //给es中索引一个文档   /company/person/1
        Index index = new Index.Builder(new Employee(1, "张三", "CC", "老实人")).index("company").type("person").build();
        jestClient.execute(index);
    }

    @Test
    void contextLoads1() throws IOException {
        //从es中检索描述字段为老实人的文档   get/company/person/1
        String queryJson = "{\n" +
                "    \"query\" : {\n" +
                "        \"match_phrase\" : {\n" +
                "            \"description\" : \"老实人\"\n" +
                "        }\n" +
                "    }\n" +
                "}";
        Search search = new Search.Builder(queryJson).addIndex("company").addType("person").build();
        SearchResult result = jestClient.execute(search);
        System.out.println(result.getJsonString());
    }
}
  • SpringData 操作 ElasticSearch(注意版本)
    此处参考上文ElasticSearch中的版本匹配说明

引入spring-boot-starter-data-elasticsearch

<!--Spring Data操作elasticsearch-->
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

application.yml配置

spring.data.elasticsearch.clusterName=docker-cluster
spring.data.elasticsearch.clusterNodes=192.168.1.5:9300

springdata操作Elasticsearch的两种方法
参考文档

@Document(indexName = "company",type ="person" )
public class Employee {
    @JestId
    private Integer id;
    private String name;
    private String department;
    private String description;

1、ElasticsearchTemplate 操作es

2、编写一个 ElasticsearchRepository 的子接口来操作ES;

public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
//CrudRepository中有很多可用的操作elasticsearch索引文档的方法,若不满足使用可以在此处重写方法}
}
@SpringBootTest
class BootSenior03ElasticsearchApplicationTests {
    @Autowired
    EmployeeRepository employeeRepository;

    @Test
    void repositoryTest(){
        /*向索引中添加文档*/
        Employee employee = new Employee(2, "李四", "SS", "海王");
        employeeRepository.save(employee);
        /*检索文档
        Optional<Employee> byId = employeeRepository.findById(1);
        System.out.println(byId.get().toString());*/
    }
}

八、ES操作–在java中的操作

使用9200:HTTP方式与ElasticSearch服务进行交互

ElasticSearch-Rest-Client:官方RestClient封装了ES操作,API层次分明,上手简单。

官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

springboot操作es

依赖:elasticsearch-rest-high-level-client

编写配置:给容器中注入RestHighLevelClient

Fragment 获取 smartRefreshLayout findViewById报错_数据_18


索引一个文档

Fragment 获取 smartRefreshLayout findViewById报错_数据_19


检索一个文档

Fragment 获取 smartRefreshLayout findViewById报错_elasticsearch_20

九、ES的使用场景(数据存储在内存中)

9.1用作检索

9.1.1商品的上架功能将商品数据存储到es中

  • 分析es数据模型,并根据对应模型创建javabean(skuEsModel)
    若内存不够用可采取分布式集群,但内存比硬盘成本贵,所在存储商品信息到es存储中应考虑存哪些数据应保存,除了sku的基本信息id,价格,品牌,销量,分类,商品标题等常用来做查询条件的字段,还应保存商品规格;
  • 组装skuEsModel(抽取的商品es模型)数据
  • Fragment 获取 smartRefreshLayout findViewById报错_字段_21


  • 将skuEsModel数据存储到es中
  • Fragment 获取 smartRefreshLayout findViewById报错_数据_22


9.1.2商品的全局检索功能

  1. 用作日志分析(ELK)