ElasticSearch【从入门到服务器部署项目案例】详细教程

了解 百度 , 谷歌 的搜索技术

什么是搜索?

计算机根据用户输入的关键词进行匹配,从已有的数据库中摘录出相关的记录反馈给用户。

线性匹配:

select * from item where title like ’%小米%‘

新业务需求

  • 比如,用户在百度文本框中输入,吃饭睡觉写程序,会出现的以下结果:
    在这里插入图片描述
    在这里插入图片描述
    从结果可以看出,百度搜索具备以下明显特点:

    1、即使在相关结果数量接近6940万时,也能快速得出结果。Google搜索相关数量有769万时,竟然以0.3秒响应出结果,可见效率之快。

    2、搜索的结果不仅仅局限于完整的“吃饭睡觉写程序”这一短语,而是将此短语拆分成,“写程序”,“吃饭”,“睡觉”,“程序”等关键字。

    3、对拆分后的搜索关键字进行标红显示。

    4、即使只满足部分关键字也能查询出来

    5、即使输错一两个字母也能查询出来,例如:搜索facebool,能查询到Facebook

    问题:上述功能,使用普通的关系型数据库, 搜索能够方便实现吗?

ElasticSearch搜索引擎

在这里插入图片描述

  • 搜索引擎(search engine)是一种信息检索系统,旨在协助搜索存储在计算机系统中的信息。

搜索引擎按照功能通常分为垂直搜索和综合搜索。

​ 1. 垂直搜索是指专门针对某一类信息进行搜索。例如:会搜网 主要做商务搜索的,并且提供商务信息。除此之外还有爱看图标网、职友集等。

​ 2. 综合搜索是指对众多信息进行综合性的搜索。例如:百度、谷歌、搜狗、360搜索等。

​ 3. 站内搜索是指对网站内的信息进行的搜索。例如:京东、招聘网站等

倒排索引

搜索引擎目前主流的实现原理:倒排索引技术

  • 倒排索引又叫反向索引(如下图)以字或词为关键字进行索引,表中关键字所对应的记录表项,记录了出现这个字或词的所有文档,每一个表项记录该文档的编号和关键字在该文档中出现的位置情况。
    在这里插入图片描述

  • 在实际的运用中,我们可以对数据库中原始的数据结构(如:商品表),在业务空闲时,事先生成文档列表(左图)及倒排索引区域(右图)

  • 用户有查询需求时,先访问倒排索引数据区域(右图),得出文档编号后,通过文档编号即可快速,准确的通过左图找到具体的文档内容

  • 例如:用户输入“跳槽”关键字,先到右图的索引区查询,找到1,4;再根据id=1和id=4到左图找到两条记录。整个过程走的都是索引,比传统的链式匹配更加快速。

了解lucene

倒排索引技术只是底层原理,我们可以自己写代码实现。也可以使用开源组织写好的方案:lucene。

官网:http://lucene.apache.org

  • Lucene是一套用于全文检索和搜寻的开源程序库,由Apache软件基金会支持和提供

  • Lucene提供了一个简单却强大的应用程序接口(API),能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免费开放源代码工具

  • Lucene并不是现成的搜索引擎产品,但可以用来制作搜索引擎产品。例如:solr和elasticsearch

什么是全文检索

全文数据库是全文检索系统的主要构成部分。所谓全文数据库是将一个完整的信息源的全部内容转化为计算机可以识别、处理的信息单元而形成的数据集合。全文数据库不仅存储了信息,而且还有对全文数据进行词、字、段落等更深层次的编辑、加工的功能,而且所有全文数据库无一不是海量信息数据库。
倒排索引是全文检索技术的一种实现方式。

elasticsearch

lucene只是一个提供全文搜索功能类库的核心工具包,而真正使用它还需要一个完善的服务框架搭建起来的应用。

lucene是类似于servlet,而搜索引擎就是tomcat 。

  • 目前市面上流行的搜索引擎软件,主流的就两款:elasticsearchsolr。这两款都是基于lucene搭建的,可以独立部署启动的搜索引擎服务软件。由于内核相同,所以两者除了服务器安装、部署、管理、集群以外,对于数据的操作,修改、添加、保存、查询等等都十分类似。就好像都是支持sql语言的两种数据库软件。只要学会其中一个另一个很容易上手。
  • 官网地址 : https://db-engines.com/en/ranking
    在这里插入图片描述
  • 从实际企业使用情况来看,elasticSearch的市场份额逐步在取代solr,国内百度、京东、新浪都是基于elasticSearch实现的搜索功能。国外就更多了 像维基百科、GitHub、Stack Overflow等等也都是基于ES的。
elastic
  • Elastic官网:https://www.elastic.co/cn/
  • 中文文档:https://elasticsearch.apachecn.org/#/
    在这里插入图片描述
  • Elastic有一条完整的产品线及解决方案:Elasticsearch、Kibana、Logstash等,前面说的三个就是大家常说的ELK技术栈。实现企业海量日志的处理分析的解决方案。大数据领域的重要一份子。

在这里插入图片描述

elasticsearch

在这里插入图片描述
最新版本7.7.1, 因为更新比较快,所以下面使用的是稳定版本6.8.1。

下载

官网下载地址如下:

可以去官网下载特定版本,建议6.8.1版本

注意:kibana、elasticsearch和IK分词器的版本号要一致,否则可能带来兼容性问题

另外,需要 jdk1.8 以上环境。

安装 elasticsearch

  1. 将下载好的elasticsearch和kibana拷贝到/opt/es/目录下
    在这里插入图片描述
  2. 安装elasticsearch:rpm -ivh elasticsearch-6.8.1.rpm
    在这里插入图片描述安装遇到问题
    在这里插入图片描述解决方案
    使用软连接解决
ln -s $JAVA_HOME/bin/java /usr/bin/java
ln -s $JAVA_HOME/bin/javac /usr/bin/javac

在这里插入图片描述

  1. 找到jdk的安装目录, 为elasticsearch配置jdk:vim /etc/sysconfig/elasticsearch
    在这里插入图片描述
    在这里插入图片描述

配置elasticsearch

  1. 切换到 /etc/elasticsearch 目录下,看到两个配置文件 jvm.optionselasticsearch.yml
    在这里插入图片描述
  2. 首先修改 jvm.options 。elasticsearch默认占用所有内存,导致虚拟机很慢,可以改的小一点。[ 默认是1G ]

vim /etc/elasticsearch/jvm.options

在这里插入图片描述
两个值必须相等

  • 修改 elasticsearch.yml 配置文件
  • 每行必须顶格,不能有空格
  • “:”后面必须有一个空格

vim /etc/elasticsearch/elasticsearch.yml

  1. 集群名称,同一集群名称必须相同(可选,集群必须配置)
    在这里插入图片描述
  2. 单个节点名称 (可选,集群必须配置)
    在这里插入图片描述
  3. 默认只允许本机访问,修改为 0.0.0.0 后则可以远程访问;
  4. 端口使用默认:9200
    在这里插入图片描述
  5. 把 bootstrap 自检程序关掉

bootstrap.memory_lock: false
bootstrap.system_call_filter: false

在这里插入图片描述
6. 配置集群列表,这里只有一个。可以配置计算机名,也可以配置ip [ 建议配主机名 , 因为ip可能会变所以配主机名称 ]
首先查看主机名 : hostname
在这里插入图片描述
主机名是你计算机名,一定不可以写错!!
在这里插入图片描述
以上 ElasticSearch 基本配置完成了

重启
  1. 启动 elasticsearch:systemctl start elasticsearch
  2. 查看状态 : systemctl status elasticsearch
    在这里插入图片描述

如果启动未成功,请去查看相关日志

vim /var/log/elasticsearch/{cluster-name}.log

例如:这里cluster-name配置的是 my-es,那么就是指:vim /var/log/elasticsearch/my-es.log 文件
在这里插入图片描述

测试

curl http://localhost:9200

[root@centos elasticsearch]# curl http://localhost:9200
{
  "name" : "node-1",
  "cluster_name" : "my-application",
  "cluster_uuid" : "NVxe9XcoS2aqWn_cjt4Mag",
  "version" : {
    "number" : "6.8.1",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "1fad4e1",
    "build_date" : "2019-06-18T13:16:52.517138Z",
    "build_snapshot" : false,
    "lucene_version" : "7.7.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}
[root@centos elasticsearch]# 

如果可以返回以上 json数据就证明配置没有问题
如果防火墙也关闭了, 浏览器也可以正常显示的 , 如图
在这里插入图片描述

cluster_block_exception

vim /etc/elasticsearch/elasticsearch.yml

cluster.routing.allocation.disk.threshold_enabled: false

安装kibana

  1. 进入 cd /opt/es 目录下解压
    在这里插入图片描述
  2. 进入 cd kibana-6.8.1-linux-x86_64/config 修改 kibana.yml 配置文件,允许访问的ip地址
  3. 默认端口 : 5601
    在这里插入图片描述
    7行 修改为虚拟机IP地址
    在这里插入图片描述
    28行 配置elasticsearch服务器列表:
    在这里插入图片描述
启动:
  1. 切换到 kibanabin目录下
    在这里插入图片描述
  2. 因为 kibana 本身就是一个 springboot 项目

./kibana # 阻塞的方式启动, 会输出日志,并独占当前窗口
nohup ./kibana & # 后台启动

日志文件就生成在bin目录下:
在这里插入图片描述

测试:
  • 浏览器访问 : http://虚拟机IP:5601 , 如图
    启动的时候可能比较慢, 因为会去加载ElasticSearch里面的数据
    在这里插入图片描述
    在这里插入图片描述

  • 点击左边菜单 DevTools ,
    在这里插入图片描述

  • 因为这个 kibana 发送命令的时候都是 restful 风格的, 所以要通过json的方式发送数据请求
    在这里插入图片描述

控制台测试 :

在Console中,执行 get _cluster/health 可以查看状态

  • 右边的结果中,status 为 yellow或者green

  • 表示es启动正常,并且与kibana连接正常。
    在这里插入图片描述

kibana 就相当于ElasticSearch 的客户端, 在这里面就可以发送命令, 交给 ElasticSearch 执行, 执行成功之后 ElasticSearch 就会将执行的结果返回给 kibana 在控制台显示, 并且这个工具的提示功能特别强大

IK分词器

  • 下面是自带的分词器 , 处理显示的结果
GET _analyze
{
  "text": "我们都是中国人"
}

在这里插入图片描述

  • 中文分词器
    elasticsearch 本身自带的中文分词,就是单纯把中文一个字一个字的分开,根本没有词汇的概念。但是实际应用中,用户都是以词汇为条件,进行查询匹配的,如果能够把文章以词汇为单位切分开,那么与用户的查询条件能够更贴切的匹配上,查询速度也更加快速。
  • 因此一般我们会用第三方提供的分词器:在这里插入图片描述
    IK分词器使用最多。
介绍
  • Lucene的IK分词器早在2012年已经没有维护了,现在我们要使用的是在其基础上维护升级的版本,并且开发为ElasticSearch的集成插件了,与Elasticsearch一起维护升级,版本也保持一致:6.8.1。
  • elasticsearch 版本要和 ik 分词器的版本保持一致
下载
安装
  • 将下载好的zip包到 /usr/share/elasticsearch/plugins 目录下
  • 解压并指定目录 -d ik-analyzer

unzip elasticsearch-analysis-ik-6.8.1.zip -d ik-analyzer

在这里插入图片描述

  • 解压完后一定要 删除压缩包
    在这里插入图片描述
测试
  • 重启elasticsearch

systemctl restart elasticsearch.service

  • 打开浏览器, 指定IK分词器 : "analyzer": "ik_smart" 在次测试
GET _analyze
{
  "analyzer": "ik_smart", 
  "text": "我们都是中国人"
}
  • 如图
    在这里插入图片描述
  • ik分词器还提供了更详尽的分词方式:ik_max_word
    在这里插入图片描述
自定义词库
  • 中文语言在不断发展,新的词汇不断涌现,怎么不断完善分词需求?
  • ik分词器提供了重要的扩展能力:
  • 扩展词典(新创建词功能): 有些词IK分词器不识别 例如:“尚硅谷”,“蓝瘦香菇”,“碉堡了”
  • 停用词典(停用某些词功能): 有些词不需要建立索引 例如:“哦”,“啊”,“的”
  • elasticsearch 加载 ik 分词器插件时,ik会读取一个配置文件,这个配置文件在ik分词器根目录的 config 目录下:
    在这里插入图片描述
  • 使用 vim IKAnalyzer.cfg.xml 打开编辑
    在这里插入图片描述
这里有两种方式配置扩展词典和停用词典:
  1. 本地方式:ext_dict配置扩展词典,ext_stopwords配置停用词典。
  2. 远程方式:tomcat或者nginx

第一种方式每次修改词典都要重启搜索服务,不推荐。推荐使用nginx的方式,并发量大,修改内容不需要重启。

Nginx 安装
第一步:利用nginx搭建远程词库。
  • 安装好 nginx 后进入nginx目录下 编辑 nginx.conf 文件

vim /usr/local/nginx/conf/nginx.conf

  • 如图
    在这里插入图片描述
  • 需要在nginx根目录下创建对应的 elasticsearch目录编辑

cd /usr/local/nginx/
mkdir -p /usr/local/nginx/elasticsearch/compile

  • 如图
    在这里插入图片描述
  • 进入 cd elasticsearch/compile/ 目录下创建 compile_dict.txt
  • vim compile_dict.txt , 随便自定义词条添加
    在这里插入图片描述
重启 Nginx
  • 启动 nginx : nginx
  • 重新加载 nginx配置文件 : nginx -s reload
  • 浏览器访问
    在这里插入图片描述
第二步:在ik分词器中引用远程词库
  • 进入ik分词器的conf目录:

cd /usr/share/elasticsearch/plugins/ik-analyzer/config/

  • 编辑 vim IKAnalyzer.cfg.xml 配置文件引入刚才自定义的字典文件
    在这里插入图片描述
重启elasticsearch服务
  • 重启再次测试 : systemctl restart elasticsearch.service
  • 如图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    添加新词条后,es只会对新增的数据用新词分词。历史数据是不会重新分词的。如果想要历史数据重新分词。需要执行:

POST {index}/_update_by_query?conflicts=proceed

elasticsearch基本操作

Elasticsearch也是基于Lucene的全文检索库,本质也是存储数据,很多概念与MySQL类似的。

说明
cluster整个elasticsearch 默认就是集群状态,整个集群是一份完整、互备的数据。
node集群中的一个节点,一般只一个进程就是一个node
shard分片,即使是一个节点中的数据也会通过hash算法,分成多个片存放,默认是5片。
index索引。相当于rdbms的database, 对于用户来说是一个逻辑数据库,虽然物理上会被分多个shard存放,也可能存放在多个node中。
type类似于rdbms的table,但是与其说像table,其实更像面向对象中的class , 同一Json的格式的数据集合。
document文档。类似于rdbms的 row、面向对象里的object
field字段。相当于字段、属性
mappings映射。字段的数据类型、属性、是否索引、是否存储等特性

对比关系:

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

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

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

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

数据结构对比

public class  Movie {
    String id;
    String name;
    Double doubanScore;
    List<Actor> actorList;
}

public class Actor{
    String id;
    String name;
}

这两个对象如果放在关系型数据库保存,会被拆成2张表,但是elasticsearch是用一个json来表示一个document

所以他保存到es

{
    “id”:1,
    “name”:”operation red sea”,
    “doubanScore”:8.5,
    “actorList”:[  
        {“id”:1,”name”:”zhangyi”},
        {“id”:2,”name”:”haiqing”},
        {“id”:3,”name”:”zhanghanyu”}
    ]
}

要注意的是:Elasticsearch本身就是分布式的,因此即便你只有一个节点,Elasticsearch默认也会对你的数据进行分片和副本操作,当你向集群添加新数据时,数据也会在新加入的节点中进行平衡。

索引操作(indeces)

查询索引
  • 查看es中有哪些索引库:

GET /_cat/indices?v

在这里插入图片描述

表头的含义

字段名含义说明
healthgreen(集群完整) yellow(单点正常、集群不完整) red(单点不正常)
status是否能使用
index索引名
uuid索引统一编号
pri主节点几个
rep从节点几个
docs.count文档数
docs.deleted文档被删了多少
store.size整体占空间大小
pri.store.size主节点占
创建索引

PUT /索引名

  • 参数可选:指定分片及副本,默认分片为5,副本为2。
{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 2
      }
}
  • 创建成功 !!
    在这里插入图片描述
  • 再次查询,可以看到刚刚创建的索引:

GET /hello

  • 查询所有的 : GET /*
删除索引

DELETE /索引库名

映射配置(_mapping)

索引有了,接下来肯定是添加数据。但是,在添加数据之前必须定义映射。

什么是映射?

映射是定义文档的过程,文档包含哪些字段,这些字段是否保存,是否索引,是否分词等

只有配置清楚,Elasticsearch才会帮我们进行索引库的创建(不一定)

  • 创建映射字段
PUT /索引库名/_mapping/类型名称
{
  "properties": {
    "字段名": {
      "type": "类型",
      "index": true,
      "store": true,
      "analyzer": "分词器"
    }
  }
}

类型名称:就是前面将的type的概念,类似于数据库中的不同表

字段名:类似于列名,properties下可以指定许多字段。

每个字段可以有很多属性。例如:

  • type:类型,可以是text、long、short、date、integer、object、keyword等

    ​ 注意:keyword也表示文本,用来保存类似邮箱、地址、状态等,不会分词但是常用。

  • index:是否索引,默认为true

  • store:是否存储,默认为false

  • analyzer:分词器,这里使用ik分词器:ik_max_word或者ik_smart

发起请求:
PUT hello/_mapping/goods
{
  "properties": {
    "title": {
      "type": "text",
      "analyzer": "ik_max_word"
    },
    "images": {
      "type": "keyword",
      "index": "false"
    },
    "price": {
      "type": "long"
    }
  }
}

响应结果:

{
  "acknowledged" : true
}

在这里插入图片描述

查看映射关系

  • 语法 GET /索引库名/_mapping
    在这里插入图片描述
字段属性详解
  • type
  • Elasticsearch中支持的数据类型非常丰富:

我们说几个关键的:

  • String类型,又分两种:

    • text:可分词,不可参与聚合
    • keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合
  • Numerical:数值类型,分两类

    • 基本数据类型:long、interger、short、byte、double、float、half_float
    • 浮点数的高精度类型:scaled_float
      • 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。
  • Date:日期类型

    elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。

index

index影响字段的索引情况。

  • true:字段会被索引,则可以用来进行搜索。默认值就是true
  • false:字段不会被索引,不能用来搜索

index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。

但是有些字段是我们不希望被索引的,比如商品的图片信息,就需要手动设置index为false。

store

是否将数据进行额外存储。

  • Elasticsearch在创建文档索引时,会将文档中的原始数据备份,保存到一个叫做_source的属性中。而且我们可以通过过滤_source来选择哪些要显示,哪些不显示。
  • 而如果设置store为true,就会在_source以外额外存储一份数据,多余,因此一般我们都会将store设置为false,事实上,store的默认值就是false。

新增文档(document)

  • 有了索引、类型和映射,就可以对文档做增删改查操作了。
  • 自动生成id
    语法
POST /索引库名/类型名
{
    "key":"value"
}

示例:

POST /hello/goods
{
  "title": "华为P40PRO",
  "images": "https://res.vmallres.com/pimages/detailImg/2020/05/06/30876E629D665CE7DA18C13A3C7E7D150F469AC8AEC0A4E6.jpg",
  "price": 4488
}

在这里插入图片描述
查询看看结果:
在这里插入图片描述

  • _source:源文档信息,所有的数据都在里面。
  • _id:这条文档的唯一标示,与文档自己的id字段没有关联

自定义id

  • 如果我们想要自己新增的时候指定id,可以这么做:
POST /索引库名/类型/id值
{
    ...
}

在这里插入图片描述
查询得到两条数据:iPhone 11 手机的id是我们指定的id
在这里插入图片描述

智能判断

事实上Elasticsearch非常智能,你不需要给索引库设置任何mapping映射,它也可以根据你输入的数据来判断类型,动态添加数据映射。

测试一下:

POST /hello/goods/2
{
    "title":"小米手机",
    "images":"http://image.jd.com/12479122.jpg",
    "price":2899,
    "stock": 200,
    "saleable":true,
    "attr": {
        "category": "手机",
        "brand": "小米"
    }
}

自动对判断添加对应的数据类型
来看结果:GET /atguigu/_search
在这里插入图片描述

  • 再看下索引库的映射关系: GET /atguigu/_mapping

  • stock,saleable,attr都被成功映射了。

  • 如果是字符串类型的数据,会添加两种类型:text + keyword。如上例中的category 和 brand

修改数据

修改数据分为,整体覆盖和修改某一个字段。

整体覆盖
  • id对应文档存在,则修改
  • id对应文档不存在,则新增

比如,我们把id为2的数据进行修改:

PUT /hello/goods/2
{
    "title":"超米手机",
    "images":"http://image.jd.com/12479122.jpg",
    "price":2999,
    "stock": 200,
    "saleable":true,
    "attr": {
        "category": "手机",
        "brand": "小米"
    }
}

查看结果 : GET /hello/goods/2
在这里插入图片描述
这种方式必须有所有字段,否则会导致更新后的数据字段缺失。

更新字段

更新使用POST请求
语法:

POST /{index}/{type}/{id}/_update
{
	"doc": {
		字段名: 字段值
	}
}

在这里插入图片描述
查询更新后的结果
在这里插入图片描述

删除数据

删除使用DELETE请求,同样,需要根据id进行删除:
语法

DELETE /索引库名/类型名/id值

首先查询到id, 下面删除默认生成的id数据
在这里插入图片描述
删除完成 ,就剩两条记录了
在这里插入图片描述

查询

查询所有:

GET /{index}/_search

根据id查询:

GET /{index}/{type}/{id}

在这里插入图片描述
除了上述简单查询之外。elasticsearch作为搜索引擎,最复杂最强大的功能就是搜索查询功能。包括:匹配查询、词条查询、模糊查询、组合查询、范围查询、高亮、排序、分页等等查询功能。

基本查询语法如下:

GET /索引库名/_search
{
    "query":{
        "查询类型":{
            "查询条件":"查询条件值"
        }
    }
}

这里的query代表一个查询对象,里面可以有不同的查询属性

  • 查询类型:
    • 例如:match_allmatchtermrange 等等
  • 查询条件:查询条件会根据类型的不同,写法也有差异,后面详细讲解

查询结果:

  • took:查询花费时间,单位是毫秒
  • time_out:是否超时
  • _shards:分片信息
  • hits:搜索结果总览对象
    • total:搜索到的总条数
    • max_score:所有结果中文档得分的最高分
    • hits:搜索结果的文档对象数组,每个元素是一条搜索到的文档信息
      • _index:索引库
      • _type:文档类型
      • _id:文档id
      • _score:文档得分
      • _source:文档的源数据
数据准备
POST /hello/goods/_bulk
{"index":{"_id":1}}
{ "title":"小米手机", "images":"http://image.jd.com/12479122.jpg", "price":1999, "stock": 200, "attr": { "category": "手机", "brand": "小米" } }
{"index":{"_id":2}}
{"title":"超米手机", "images":"http://image.jd.com/12479122.jpg", "price":2999, "stock": 300, "attr": { "category": "手机", "brand": "小米" } }
{"index":{"_id":3}}
{ "title":"小米电视", "images":"http://image.jd.com/12479122.jpg", "price":3999, "stock": 400, "attr": { "category": "电视", "brand": "小米" } }
{"index":{"_id":4}}
{ "title":"小米笔记本", "images":"http://image.jd.com/12479122.jpg", "price":4999, "stock": 200, "attr": { "category": "笔记本", "brand": "小米" } }
{"index":{"_id":5}}
{ "title":"华为手机", "images":"http://image.jd.com/12479122.jpg", "price":3999, "stock": 400, "attr": { "category": "手机", "brand": "华为" } }
{"index":{"_id":6}}
{ "title":"华为笔记本", "images":"http://image.jd.com/12479122.jpg", "price":5999, "stock": 200, "attr": { "category": "笔记本", "brand": "华为" } }
{"index":{"_id":7}}
{ "title":"荣耀手机", "images":"http://image.jd.com/12479122.jpg", "price":2999, "stock": 300, "attr": { "category": "手机", "brand": "华为" } }
{"index":{"_id":8}}
{ "title":"oppo手机", "images":"http://image.jd.com/12479122.jpg", "price":2799, "stock": 400, "attr": { "category": "手机", "brand": "oppo" } }
{"index":{"_id":9}}
{ "title":"vivo手机", "images":"http://image.jd.com/12479122.jpg", "price":2699, "stock": 300, "attr": { "category": "手机", "brand": "vivo" } }
{"index":{"_id":10}}
{ "title":"华为nova手机", "images":"http://image.jd.com/12479122.jpg", "price":2999, "stock": 300, "attr": { "category": "手机", "brand": "华为" } }

匹配查询(match)

匹配所有

GET /hello/_search
{
    "query":{
        "match_all": {}
    }
}
  • query:代表查询对象
  • match_all:代表查询所有
条件匹配 模糊匹配
GET /hello/_search
{
  "query": {
    "match": {
      "title": "小米手机"
    }
  }
}

在这里插入图片描述

  • 查询品牌是小米的
    在这里插入图片描述
条件查询

查询出很多数据,不仅包括小米手机,而且与小米或者手机相关的都会查询到,说明多个词之间是or的关系。

某些情况下,我们需要更精确查找,我们希望这个关系变成and,可以这样做:

GET /hello/_search
{
  "query": {
    "match": {
      "title": {
        "query": "小米手机",
        "operator": "and"
      }
    }
  }
}

在这里插入图片描述

短句匹配

按短语查询,不再利用分词技术,直接用短语在原始数据中匹配
在这里插入图片描述

多字段匹配

match只能根据一个字段匹配查询,如果要根据多个字段匹配查询可以使用multi_match
在这里插入图片描述

词条查询(term)

term 查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些未分词的字符串。

GET /hello/_search
{
    "query":{
        "term":{
            "price": 4999
        }
    }
}

在这里插入图片描述

多词条查询

terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件:
在这里插入图片描述

范围查询(range)

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

GET /hello/_search
{
    "query":{
        "range": {
            "price": {
                "gte":  1000,
                "lt":   3000
            }
    	}
    }
}

在这里插入图片描述
range查询允许以下字符:

操作符说明
gt大于
gte大于等于
lt小于
lte小于等于

模糊查询(fuzzy)

  • fuzzy 允许用户搜索词条与实际词条的拼写出现偏差,但是偏差的编辑距离不得超过2:
GET /atguigu/_search
{
  "query": {
    "fuzzy": {
      "title": "oppe"
    }
  }
}

在这里插入图片描述
上面的查询,也能查询到apple手机

GET /hello/_search
{
  "query": {
    "fuzzy": {
      "title": {
        "value": "oppe",
        "fuzziness": 1
      }
    }
  }
}

可以通过fuzziness来指定允许的编辑距离:
在这里插入图片描述
编辑距离:从错误的词到正确词条需要修改的次数。例如:oppe—>oppo,需要修改一次,编辑距离就是1。

elasticsearch支持的最大编辑距离是2。

布尔组合(bool)

布尔查询又叫组合查询

bool把各种其它查询通过must(与)、must_not(非)、should(或)的方式进行组合

GET /hello/_search
{
    "query":{
        "bool":{
        	"must": [
        	  {
        	    "range": {
        	      "price": {
        	        "gte": 1000,
        	        "lte": 3000
        	      }
        	    }
        	  },
        	  {
        	    "range": {
        	      "price": {
        	        "gte": 2000,
        	        "lte": 4000
        	      }
        	    }
        	  }
        	]
        }
    }
}

在这里插入图片描述
注意:一个组合查询里面只能出现一种组合,不能混用

过滤(filter)

所有的查询都会影响到文档的评分及排名。如果我们需要在查询结果中进行过滤,并且不希望过滤条件影响评分,那么就不要把过滤条件作为查询条件来用。而是使用filter方式:

GET /hello/_search
{
  "query": {
    "bool": {
      "must": {
        "match": { "title": "小米手机" }
      },
      "filter": {
        "range": {
          "price": { "gt": 2000, "lt": 3000 }
        }
      }
    }
  }
}

在这里插入图片描述
注意:filter中还可以再次进行bool组合条件过滤。

排序(sort)

sort 可以让我们按照不同的字段进行排序,并且通过order指定排序的方式

GET /hello/_search
{
  "query": {
    "match": {
      "title": "小米手机"
    }
  },
  "sort": [
    {
      "price": { "order": "desc" }
    },
    {
      "_score": { "order": "desc"}
    }
  ]
}

在这里插入图片描述

分页(from/size)

GET /hello/_search
{
  "query": {
    "match": {
      "title": "小米手机"
    }
  },
  "from": 2,
  "size": 2
}

from:从那一条开始

size:取多少条

高亮(highlight)

查看百度高亮的原理:
发现:高亮的本质是给关键字添加了<em>标签,在前端再给该标签添加样式即可。
在这里插入图片描述

GET /hello/_search
{
  "query": {
    "match": {
      "title": "小米"
    }
  },
  "highlight": {
    "fields": {"title": {}}, 
    "pre_tags": "<em>",
    "post_tags": "</em>"
  }
}

在这里插入图片描述
fields:高亮字段

pre_tags:前置标签

post_tags:后置标签

结果过滤(_source)

默认情况下,elasticsearch在搜索的结果中,会把文档中保存在_source的所有字段都返回。

如果我们只想获取其中的部分字段,可以添加_source的过滤

GET /hello/_search
{
  "_source": ["title","price"],
  "query": {
    "term": {
      "price": 2699
    }
  }
}

在这里插入图片描述
返回结果,只有两个字段:

聚合(aggregations)

聚合可以让我们极其方便的实现对数据的统计、分析。例如:

  • 什么品牌的手机最受欢迎?
  • 这些手机的平均价格、最高价格、最低价格?
  • 这些手机每月的销售情况如何?

实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现实时搜索效果。

基本概念

Elasticsearch中的聚合,包含多种类型,最常用的两种,一个叫,一个叫度量

桶(bucket)

桶的作用,是按照某种方式对数据进行分组,每一组数据在ES中称为一个,例如我们根据国籍对人划分,可以得到中国桶英国桶日本桶……或者我们按照年龄段对人进行划分:010,1020,2030,3040等。

Elasticsearch中提供的划分桶的方式有很多:

  • Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
  • Histogram Aggregation:根据数值阶梯分组,与日期类似
  • Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
  • Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组
  • ……

bucket aggregations 只负责对数据进行分组,并不进行计算,因此往往bucket中往往会嵌套另一种聚合:metrics aggregations即度量

度量(metrics)

分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量

比较常用的一些度量聚合方式:

  • Avg Aggregation:求平均值
  • Max Aggregation:求最大值
  • Min Aggregation:求最小值
  • Percentiles Aggregation:求百分比
  • Stats Aggregation:同时返回avg、max、min、sum、count等
  • Sum Aggregation:求和
  • Top hits Aggregation:求前几
  • Value Count Aggregation:求总数
  • ……

聚合为桶

首先,我们按照手机的品牌attr.brand.keyword来划分

GET /hello/_search
{
    "size" : 0,
    "aggs" : { 
        "brands" : { 
            "terms" : { 
              "field" : "attr.brand.keyword"
            }
        }
    }
}

在这里插入图片描述

  • size: 查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率
  • aggs:声明这是一个聚合查询,是aggregations的缩写
    • brands:给这次聚合起一个名字,任意。
      • terms:划分桶的方式,这里是根据词条划分
        • field:划分桶的字段,从数据属性中挑选的

桶内度量

前面的例子告诉我们每个桶里面的文档数量,这很有用。 但通常,我们的应用需要提供更复杂的文档度量。 例如,每种品牌手机的平均价格是多少?

因此,我们需要告诉Elasticsearch使用哪个字段使用何种度量方式进行运算,这些信息要嵌套在内,度量的运算会基于内的文档进行

现在,我们为刚刚的聚合结果添加 求价格平均值的度量:

GET /hello/_search
{
    "size" : 0,
    "aggs" : { 
        "brands" : { 
            "terms" : { 
              "field" : "attr.brand.keyword"
            },
            "aggs":{
                "avg_price": { 
                   "avg": {
                      "field": "price" 
                   }
                }
            }
        }
    }
}

在这里插入图片描述

  • aggs:我们在上一个aggs(brands)中添加新的aggs。可见度量也是一个聚合
  • avg_price:聚合的名称
  • avg:度量的类型,这里是求平均值
  • field:度量运算的字段

桶内嵌套桶

刚刚的案例中,我们在桶内嵌套度量运算。事实上桶不仅可以嵌套运算, 还可以再嵌套其它桶。也就是说在每个分组中,再分更多组。

比如:我们想统计每个品牌都生产了那些产品,按照attr.category.keyword字段再进行分桶

GET /hello/_search
{
    "size" : 0,
    "aggs" : { 
        "brands" : { 
            "terms" : { 
              "field" : "attr.brand.keyword"
            },
            "aggs":{
                "avg_price": { 
                   "avg": {
                      "field": "price" 
                   }
                },
                "categorys": {
                  "terms": {
                    "field": "attr.category.keyword"
                  }
                }
            }
        }
    }
}

在这里插入图片描述

  • 我们可以看到,新的聚合categorys被嵌套在原来每一个brands的桶中。
  • 每个品牌下面都根据 attr.category.keyword字段进行了分组
  • 我们能读取到的信息:
    • 华为有4中产品
    • 华为产品的平均售价是 3999.0美元。
    • 其中3种手机产品,1种笔记本产品

Java客户端(jest)

目前市面上有两类客户端

  • 一类是TransportClient 为代表的ES原生客户端,不能执行原生dsl语句必须使用它的Java api方法。

  • 另外一种是以Rest Api为主的missing client,最典型的就是jest。 这种客户端可以直接使用dsl语句拼成的字符串,直接传给服务端,然后返回json字符串再解析。

  • 两种方式各有优劣,但是最近elasticsearch官网,宣布计划在7.0以后的版本中废除TransportClient。以RestClient为主。

  • 所以在官方的RestClient 基础上,进行了简单包装的Jest客户端,就成了首选,而且该客户端也与springboot完美集成。

  1. 创建springboot 的 module
  2. 引入依赖:
<!-- Java 操作 elasticsearch 的客户端 -->
<dependency>
  <groupId>io.searchbox</groupId>
  <artifactId>jest</artifactId>
  <version>6.3.1</version>
</dependency>

<!-- elasticsearch 驱动包 -->
<dependency>
  <groupId>org.elasticsearch</groupId>
  <artifactId>elasticsearch</artifactId>
  <version>6.8.3</version>
</dependency>

需要降低springboot依赖的版本, 否则加载不到
在这里插入图片描述
3. 在application.properties中添加配置

# 指定连接 es 的服务器IP + prop
spring.elasticsearch.jest.uris=http://192.168.230.204:9200
# jest 客户端连接 es 的超时时间
spring.elasticsearch.jest.connection-timeout=10S
# jest 客户端操作 es 时的超时时间
spring.elasticsearch.jest.read-timeout=5s
# 集群情况下
#spring.elasticsearch.jest.uris[0]=http://192.168.230.204:9200
#spring.elasticsearch.jest.uris[1]=http://192.168.230.204:9200
  1. 准备Javabean , User.java
public class User {
    private String username;
    private String password;
    private Integer age;
}
  1. 测试类
添加
@Test
public void insert() throws IOException {
    User user = new User("小明", "123456", 20);
    // index : 表示索引库, type : 指定表名, id : 插入数据的 id 值 [如果不写,会默认生成一个uuid]
    Index action = new Index.Builder(user).index("users").type("user").id("1").build();
    DocumentResult result = jestClient.execute(action);
    System.out.println("result = " + result.toString());
}
结果 : result = Result: {"_index":"users","_type":"user","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}, isSucceeded: true, response code: 201, error message: null
  1. 浏览器查看, 刚才添加的数据
    在这里插入图片描述
更新
@Test
public void update() throws IOException {
     User user = new User("小明", "1949688", 26);
     Index action = new Index.Builder(user).index("users").type("user").id("1").build();
     DocumentResult result = jestClient.execute(action);
     System.out.println("result = " + result.toString());
 }
结果 : result = Result: {"_index":"users","_type":"user","_id":"1","_version":3,"result":"updated","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":2,"_primary_term":1}, isSucceeded: true, response code: 200, error message: null

在这里插入图片描述

查询
@Test
public void query() throws IOException {
    // 查询表达式
    String query="{\n" +
            "  \"query\": {\n" +
            "    \"match_all\": {}\n" +
            "  }\n" +
            "}";
    Search action = new Search.Builder(query).addIndex("users").addType("user").build();
    SearchResult result = jestClient.execute(action);
    // 直接获取到结果集
    List<User> userList = result.getSourceAsObjectList(User.class, false);
    System.out.println("userList = " + userList);
    System.out.println("-----------------------------------------------------------------");
    // 获取查询到的结果集和其它信息
    List<SearchResult.Hit<User, Void>> hits = result.getHits(User.class);
    hits.forEach(hit -> {
        System.out.println("hit.source = " + hit.source);
    });
}
结果 : userList = [User{username='小明', password='1949688', age=26}]
-----------------------------------------------------------------
hit.source = User{username='小明', password='1949688', age=26} 

查询一个:结果

@Test
public void queryById() throws IOException {
    Get user = new Get.Builder("users", "1").build();
    DocumentResult result = jestClient.execute(user);
    System.out.println("result = " + result);
}
结果: result = Result: {"_index":"users","_type":"user","_id":"1","_version":3,"_seq_no":2,"_primary_term":1,"found":true,"_source":{"username":"小明","password":"1949688","age":26}}, isSucceeded: true, response code: 200, error message: null
删除
@Test
public void delete() throws IOException {
     Delete action = new Delete.Builder("1").index("users").type("user").build();
     DocumentResult result = jestClient.execute(action);
     System.out.println(result.toString());
 }

在这里插入图片描述

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: Android OpenGL ES 3.0是一个强大的图形渲染API,用于开发Android平台上的高性能3D应用程序和游戏。从入门到精通OpenGL ES 3.0需要系统性的学习教程,以下是一个简要的学习路径: 1. 基础知识:首先需要了解OpenGL ES 3.0的基础知识,包括图形渲染管线、坐标系、顶点和片元着色器等。可以通过阅读相关的教程、书籍或者在线资源来获得这方面的知识。 2. 环境搭建:学习OpenGL ES 3.0之前,需要先搭建好学习环境。可以下载安装Android Studio和相关的开发工具,以及配置好OpenGL ES 3.0的开发环境。 3. 学习资源:寻找一些高质量的学习资源,如教程、书籍或者在线课程。可以选择一些经典的OpenGL ES 3.0教程,其中包括基础知识、实例代码和案例分析等。 4. 实践练习:学习OpenGL ES 3.0最重要的一点就是不断地进行实践练习。可以按照教程中的示例代码,逐步实现一些简单的图形渲染效果。通过实践来加深对OpenGL ES 3.0的理解,掌握各种绘制技术和渲染效果。 5. 深入研究:在掌握了基础知识和实践经验之后,可以进一步深入研究OpenGL ES 3.0的高级特性和扩展功能。包括纹理映射、着色器编程、光照和阴影效果等。可以参考一些专业书籍和高级教程来进一步提升自己的技术水平。 6. 项目实践:最后一步是通过实际项目的实践来巩固所学的知识。可以尝试开发一些简单的游戏或者应用程序,利用OpenGL ES 3.0来实现复杂的图形渲染效果。通过实际项目的经验,可以进一步提升自己的技术能力和解决问题的能力。 总之,学习Android OpenGL ES 3.0需要系统性的学习教程,并通过不断实践和项目实践来提升自己的技术水平。只有在不断学习和实践中,才能逐步精通OpenGL ES 3.0并运用到实际开发中。 ### 回答2: Android OpenGL ES 3.0 是一种强大的图形渲染技术,用于在Android设备上创建高性能的3D图形和特效。要系统地学习和掌握Android OpenGL ES 3.0,您可以按照以下步骤: 1. 学习基础知识:首先,您需要了解计算机图形学和OpenGL ES的基本概念。这包括了解3D图形渲染的原则、OpenGL ES的架构、状态机模型等。可以通过阅读相关的教材或者参考互联网上的优质教程来学习这些内容。 2. 编程环境设置:为了开始使用Android OpenGL ES 3.0,您需要配置开发环境。这包括安装和配置Android开发工具包(Android SDK)以及适当的集成开发环境(如Android Studio)。确保您的开发环境正确设置,并具备OpenGL ES 3.0的支持。 3. 学习OpenGL ES API:学习OpenGL ES 3.0的API是掌握该技术的关键。您需要理解OpenGL ES的基本绘图函数、顶点和片段着色器编程、纹理映射等概念。可以通过查阅OpenGL ES 3.0的官方文档或参考书籍来学习这些API。 4. 实践项目:通过实践项目来巩固所学的知识。您可以从最简单的项目开始,如画一个三角形,然后逐步扩展,添加更多的图形对象和特效。这样您可以深入了解OpenGL ES 3.0的使用和性能优化。 5. 学习高级主题:一旦掌握了基础知识,您可以进一步学习OpenGL ES 3.0的高级主题。这可能包括光照、阴影、投影、深度测试和其他高级特性。这些主题的学习可以通过参考更高级的教程、专业书籍或者参与相关论坛和社区来深入研究。 6. 性能优化:了解如何优化OpenGL ES 3.0的性能也是非常重要的。您可以学习如何使用缓冲区对象、顶点缓冲区对象(VBO)、纹理压缩和其他优化技术来提高应用程序的帧率和响应速度。 总而言之,要系统学习和掌握Android OpenGL ES 3.0,您需要深入理解计算机图形学和OpenGL ES的原理,学习API的使用和性能优化技术,并通过实践项目来强化您的理解和应用能力。这需要坚持不懈的学习和实践,但通过这样的系统学习,您将能够成为一名Android OpenGL ES 3.0的专家。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智汇探长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值