目录
全文检索
什么是全文检索
全文检索流程
相关概念
索引库
document对象
field对象
term对象
ElasticSearch简介
什么是ElasticSearch
ElasticSearch相关概念
核心概念
Elasticsearch 安装
IK 分词器
安装 IK 分词器
IK分词器测试
ElasticSearch 的客户端-Kibana
Kibana下载安装
Kibana 使用
DSL语句使用
索引 *** 作
文档 *** 作
查询模式
全文检索 什么是全文检索
如果我们想要在博客平台上搜索包含“Java”关键字的文章,于是我们就需要对每一篇文章的内容都进行检索,但这些会非常消耗时间。所以我们事先将所有文章的关键词及关键词对应文章信息都存储在一些文档(索引)中,每次搜索的时候我们先在这些文档(索引)中查询关键词,查询到之后返回给用户,这样大大减少了查询所需要的时间。这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)。
由于每篇文章的内容及其结构都各不相同,所以我们称它们为“非结构化数据”。对于这种“非结构化数据”,我们通常都是采用全文检索来进行查询。
虽然创建索引的过程也是非常耗时的,但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的。
全文检索流程 相关概念 索引库索引库本质上就是存储索引的保存在磁盘上的一系列的文件,里面存储了建立好的索引信息以及文档对象。
document对象获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(document),文档中包括一个一个的域(Field),域中存储内容。每个文档都有一个唯一的编号,就是文档 id。
document对象相当于表中的一条记录。
field对象如果我们把 document 看做是数据库中一条记录的话,field 相当于是记录中的字段。field 是索引库中存储数据的最小单位。field 的数据类型大致可以分为数值类型和文本类型,一般需要查询的字段都是文本类型的,field 的还有如下属性:
是否分词:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到是否存储:将 Field 值存储在文档中,存储在文档中的 Field 才可以从 document 中获取 term对象
从文档对象中拆分出来的每个单词叫做一个Term,其实就是上文提到的关键词,不同的域中拆分出来的相同的单词是不同的term。term中包含两部分一部分是文档的域名,另一部分是单词的内容。term是创建索引的关键词对象。
ElasticSearch简介 什么是ElasticSearchElaticsearch,简称为 es, es 是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别的数据。es 也使用 Java 开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单。
ElasticSearch相关概念Elasticsearch 是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch 中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。Elasticsearch 比传统关系型数据库如下:
核心概念Relational DB -> Databases(数据库) -> Tables(表) -> Rows(行) -> Columns(列)
Elasticsearch -> Indices(索引) -> Types(类型) -> documents(文档) -> Fields(属性)
- 索引 index:相当于一个数据库,一个索引就是一个拥有几分相似特征的文档的集合,一个索引由一个名字来标识(必须全部是小写字母的),我们使用索引名对其下的文档进行 *** 作(增删改查)类型 type:相当于的数据库的表,在一个索引中,你可以定义一种或多种类型。字段 Field:相当于是数据表的字段,对文档数据根据不同属性进行的分类标识映射 mapping:mapping 是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其它就是处理 es 里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。文档 document:一个文档是一个可被索引的基础信息单元,即相当于表中的一条数据。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个 index/type 里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,但是文档必须被索引/赋予一个索引的 type。接近实时 NRT:Elasticsearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒以内)集群 cluster:一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群节点 node:一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。
和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何 Elasticsearch 节点,这时启动一个节点,会默认创建并加入一个叫做 “elasticsearch” 的集群。分片 shards:一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因:
1)允许你水平分割/扩展你的内容容量。
2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的 *** 作,进而提高性能/吞吐量复制 replicas:在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。分词器 analyzer:如上文所说,我们需要在查询文档(document)对其分析,将用户发送过来的数据分析成一个个查询的词,这便叫做分词器。es 自带的分词器是 standard,该分词器英文根据空格来分词,中文则是一字一词。
本文采用 Docker 安装,windows 安装 es 比较简单,下载 exe 安装程序直接安装即可。Linux安装可参考其他网上教程。
1、docker 镜像下载
docker pull elasticsearch:5.6.8
2、安装 es 容器
docker run -di --name=fgba_es -p 9200:9200 -p 9300:9300 elasticsearch:5.6.8
9200端口(Web管理平台端口) 9300(服务默认端口)
访问 9200 端口
3、开启远程连接
上面完成安装后,es 并不能正常使用,elasticsearch 从5版本以后默认不开启远程连接。
- 编写 sources.list 文件:
deb http://mirrors.aliyun.com/ubuntu/ xenial main deb-src http://mirrors.aliyun.com/ubuntu/ xenial main deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main deb http://mirrors.aliyun.com/ubuntu/ xenial universe deb-src http://mirrors.aliyun.com/ubuntu/ xenial universe deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates universe deb http://mirrors.aliyun.com/ubuntu/ xenial-security main deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security universe设置 apt 下载源
docker cp ~/sources.list fgba_es:/etc/apt/sources.list安装 vim 编辑器
apt-get update apt-get install vim
安装好了后,修改 elasticsearch.yml 配置,如下以上 *** 作是因为 es 容器默认使用的 Ubuntu 16.04 *** 作系统没有安装编辑器,所以需要更新下载源后进行安装编辑器
vi elasticsearch.yml
删除 transport.host 的注释以开放远程连接
在最后添加修改代码,用于修改集群名称
cluster.name: my-elasticsearch
添加跨域配置
http.cors.enabled: true http.cors.allow-origin: "*" network.host: 192.168.137.5 #你安装 es 机器的IP地址
最终配置文件如下:
其中: http.cors.enabled: true:此步为允许elasticsearch跨域访问,默认是false。 http.cors.allow-origin: "":表示跨域访问允许的域名地址(表示任意)。
重启容器
docker restart fgba_es查看是否重启成功
docker ps
如果未显示则表示未启动成功
失败的原因与我们刚才修改的配置有关,因为 elasticsearch 在启动的时候会进行一些检查,比如最多打开的文件的个数以及虚拟内存区域数量等等,如果你放开了此配置,意味着需要打开更多的文件以及虚拟内存,所以我们还需要系统调优
修改 /etc/security/limits.conf 文件 (nofile 是单个进程允许打开的最大文件个数 soft nofile 是软限制 hard nofile是硬限制 )
vi /etc/security/limits.conf
找到以下位置:
修改为如下:
如果未找到手动添加以下代码即可
* soft nofile 65536 * hard nofile 65536
修改 /etc/sysctl.conf 文件,追加内容 (限制一个进程可以拥有的 VMA (虚拟内存区域)的数量 )
vm.max_map_count=655360
执行下面命令 修改内核参数马上生效
sysctl -p
重新启动虚拟机,再次启动容器,发现已经可以启动
reboot
由于自带的 standard 分词器对中文的支持并不好,所以我们需要安装专门的中文分词器。standard 分词示例如下:
IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出 了3个大版本。最初,它是以开源项目Lucene为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的IKAnalyzer3.0则发展为 面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。
安装 IK 分词器1、IK分词器下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
2、将 IK 分词器上传到服务器上,然后解压,并改名字为 ik
unzip elasticsearch-analysis-ik-5.6.8.zip mv elasticsearch ik
3、将 IK 目录拷贝到 docker 容器的 plugins 目录下
docker cp ./ik fgba_es:/usr/share/elasticsearch/plugins
4、重启容器
docker restart fgba_esIK分词器测试
访问链接:http://192.168.137.5:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是程序员
访问链接:http://192.168.137.5:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是程序员
ElasticSearch 的客户端-Kibanaik_max_word:会将文本做最细粒度的拆分
比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。ik_smart:会做最粗粒度的拆分
比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。
在本文,我们选择比较流行且功能更加强大的 Kibana 作为客户端,其他客户端例如 elasticsearch-head 可以参照网上文章进行学习
Kibana 是一款开源的数据分析和可视化平台,它是 Elastic Stack 成员之一,设计用于和 Elasticsearch 协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索、查看、交互 *** 作。您可以很方便的利用图表、表格及地图对数据进行多元化的分析和呈现。
Kibana 可以使大数据通俗易懂。它很简单,基于浏览器的界面便于您快速创建和分享动态数据仪表板来追踪 Elasticsearch 的实时数据变化。
同样地,我们使用 docker 进行的 Kibana 下载安装
1、镜像下载
docker pull docker.io/kibana:5.6.8
2、安装kibana容器
执行如下命令,开始安装kibana容器
docker run -it -d -e ELASTICSEARCH_URL=http://192.168.137.5:9200 --name kibana -p 5601:5601 kibana:5.6.8
ELASTICSEARCH_URL=http://192.168.137.5:9200:是指链接的ES地址
5601:5601:端口号
3、访问测试
访问 http://192.168.137.5:5601 如下:
要使用Kibana,您必须至少配置一个索引。索引用于标识 Elasticsearch 索引以运行搜索和分析。它们还用于配置字段。
1、创建索引
a. 使用 Kibana 创建一个索引
输入以下代码创建名为 user 的索引,该代码会在下文进行解释
PUT /user { "mappings": { "userinfo": { "properties": { "id": { "type": "long", "store": true }, "name": { "type": "text", "store": true, "index": true, "analyzer": "ik_smart" }, "city": { "type": "text", "store": true, "index": true, "analyzer": "ik_smart" }, "age": { "type": "long" } } } } }
b. 使用 Postman Restful 接口创建索引
在 raw 中输入下面的 JSON 数据
{ "mappings": { "userinfo": { "properties": { "id": { "type": "long", "store": true }, "name": { "type": "text", "store": true, "index": true, "analyzer": "ik_smart" }, "city": { "type": "text", "store": true, "index": true, "analyzer": "ik_smart" }, "age": { "type": "long" } } } } }
发送请求创建成功后显示如下结果:
2、配置kibana
运行成功后,我们修改索引名称的匹配方式即可,下面2个选项不用勾选,修改后会自动匹配
点击 create,会展示出当前配置的索引的域信息,如下图:
域的每个标题选项分别代表如下意思:
DSL语句使用Query DSL 是一个 Java 开源框架用于构建类型安全的 SQL 查询语句。采用 API 代替传统的拼接字符串来构造查询语句。目前 Querydsl 支持的平台包括 JPA,JDO,SQL,Java Collections,RDF,Lucene, Hibernate Search。elasticSearch 提供了一整套基于 JSON 的 DSL 语言来定义查询。
索引 *** 作1、查询所有索引
GET /_cat/indices?v
示例如下:
2、新增索引
PUT 索引名
结果如下:
在新增索引时同时创建映射
PUT /user { "mappings": { "userinfo": { "properties": { "id": { "type": "long", "store": true }, "name": { "type": "text", "store": true, "index": true, "analyzer": "ik_smart" }, "city": { "type": "text", "store": true, "index": true, "analyzer": "ik_smart" }, "age": { "type": "long" } } } } }
article:为 Types(类型名),相当于在关系数据库中建一个表
id:为 Fields(字段),相当于在关系数据库表中的一个字段,其中 type 为字段类型,store 表示数据是否持久化到磁盘
title:其中 index 为是否为 Fields(字段)创建索引,analyzer 表示该字段使用的分词器
3、删除某个索引
DELETE 索引名
示例如下:
4、创建映射
PUT /blog1/article/_mapping { "properties": { "id": { "type": "long", "store": true }, "title": { "type": "text", "store": true, "index": true, "analyzer": "standard" }, "content": { "type": "text", "store": true, "index": true, "analyzer": "standard" } } }
以上代码的含义为 blog1 索引创建一个名为 article 的映射,其中的域有 id、title、content
结果如下:
5、查询索引信息
GET 索引名
示例如下:
文档 *** 作1、新增文档数据
POST /索引名/类型/id { "域名称":"值", ... }
示例如下:
多添加几条数据方便等下查询
#新增文档数据 id=2 PUT /user/userinfo/2 { "name": "王五", "age": 35, "city": "广东省中山市" } #新增文档数据 id=3 PUT /user/userinfo/3 { "name": "李四", "age": 19, "city": "广东省珠海市" } #新增文档数据 id=4 PUT /user/userinfo/4 { "name": "赵六", "age": 66, "city": "湖北省武汉市" } #新增文档数据 id=5 PUT /user/userinfo/5 { "name": "赵七", "age": 77, "city": "广东省广州市", "address": "广东省茂名市" } #新增文档数据 id=6 PUT /user/userinfo/6 { "name": "赵毅", "age": 55, "city": "广东省广州市" }
2、修改数据
a. 替换 *** 作
修改指定 id 的值
POST /索引名/类型/id { "域名称":"值", ... }
更新数据可以使用之前的增加 *** 作,这种 *** 作会将整个数据替换掉,示例如下:
b. 更新 *** 作
使用POST更新某个域的数据
POST /索引名/类型名/id/_update { "doc": { "域名称": "值" } }
示例如下:
查询文档数据
1、查询所有数据
#查询所有 GET /索引名/_search
示例如下:
2、根据ID查询
#根据ID查询 GET /索引名/类型名/id
示例如下:
3、Sort 排序
GET /索引名/_search { "sort": { "域名称": { "order": "desc(降序)/asc(升序)" } } }
示例如下:
图中的代码表示根据年龄降序查询所有数据
4、分页查询
GET /索引名/_search { "from": 起始位置, "size": 每页显示条数 }
示例如下:
查询模式图中的代码表示从第4条开始查询2条数据
1、term 查询:term主要用于分词精确匹配,如字符串、数值、日期等(不适合情况:1.列中除英文字符外有其它值 2.字符串值中有冒号或中文 3.系统自带属性如_version)
GET /索引名/_search { "query": { "term": { "域名称": 查询值 } } }
示例如下:查询 age=77 的用户
2、terms 查询:terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配 。
GET /索引名/_search { "query": { "terms": { "域名称": [ 查询值1, 查询值2, ... ] } } }
示例如下:查询 age=77,age=31 的用户
3、match 查询:match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符
GET /索引名/_search { "query": { "match": { "域名称": 查询值 } } }
示例如下:
由分词器分成了“中山市”、“湖北省”,查询 city 含有这两个词的数据
4、query_string 查询:作用同 match 查询
GET /索引名/_search { "query_string": { "default_field": "域名称", "query": 查询值 } }
示例如下:
5、range 查询:range 过滤允许我们按照指定范围查找一批数据。
GET /索引名/_search { "query": { "range": { "域名": { "gte/gt": 查询值1, "lte/lt": 查询值2 } } } }
示例如下:查询年龄在30到57之间的用户数据
gt表示> ,gte表示=>
lt表示< ,lte表示<=
6、exists 查询:exists 过滤可以用于查找拥有某个域的数据
GET /索引名/_search { "query": { "exists": { "field": "域名称" } } }
示例如下:查询存在 address 域的数据
7、bool 查询:bool 可以用来合并多个条件查询结果的布尔逻辑
它包含一下 *** 作符:
must : 多个查询条件的完全匹配,相当于 and。must_not : 多个查询条件的相反匹配,相当于 not。should : 至少有一个查询条件匹配, 相当于 or。
这些参数可以分别继承一个过滤条件或者一个过滤条件的数组
GET /索引名/_search { "query": { "bool": { "must/must_not/should": [ 查询条件1:match,range等, 查询条件2:match,range等, ... ] } } }
示例如下:match 查询城市含有广东省,并且年龄在20到99之间的
8、match_all 查询:可以查询到所有文档,是没有查询条件下的默认语句。
GET /索引名/_search { "query": { "match_all": {} } }
示例如下:
9、prefix 查询:以什么字符开头的,可以更简单地用 prefix。
GET /索引名/_search { "query": { "prefix": { "域名称": { "value": 查询值 } } } }
示例如下:查询姓赵的用户
10、multi_match 查询:multi_match 查询允许你做 match 查询的基础上同时搜索多个字段,在多个字段中同时查一个。
GET /索引名/_search { "query": { "multi_match": { "query": 查询的值, "fields": [ "域名称1", "域名称2", ... ] } } }
示例如下:查询 city、address 域含有“湖北省茂名市” 的数据
由分词器分成了“茂名市”、“湖北省”,查询 city,address 含有这两个词的数据
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)