1.全文检索基础
1.1什么是全文检索
将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引。
例如:字典。字典的拼音表和部首检字表就相当于字典的索引,对每一个字的解释是非结构化的,如果字典没有音节表和部首检字表,在茫茫辞海中找一个字只能顺序扫描。然而字的某些信息可以提取出来进行结构化处理,比如读音,就比较结构化,分声母和韵母,分别只有几种可以一一列举。于是将读音拿出来按一定的顺序排列,每一项读音都指向此字的详细解释的页数。我们搜索时按结构化的拼音搜到读音,然后按其指向的页数,便可找到我们非结构化数据也即对字的解释
这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)
虽然创建索引的过程也是非常耗时的,但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的
1.2全文检索流程
1.3相关概念
1.索引库
索引库就是存储索引的保存在磁盘上的一系列文件。里面存储了建立好的的索引信息以及文档对象
一个索引库相当于数据库中的一张表
2.doucument对象
获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档中包括一个一个的域(Field),域中存储内容,每个文档都有一个唯一地编号,就是文档id。
document相当于表中的一条记录
3.field对象
如果我们把document看作是数据库中的一条记录的话,field相当于是记录中的字段。field是索引库中存储数据的最小单位,field的数据类型大致可以分为数值类型和文本类型,一般需要查询的字段都是文本类型的,field还有如下属性:
- 是否分词:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询
- 是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可以搜索到
- 比如:商品名称、商品简介分析后进行索引,订单号,身份证号不用分词但需要索引,这些将来都要作为查询条件
- 是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取
4.term对象
从文档对象中长风出来的每个单词叫一个Term,不同的域中仓分出来的相同的单次是不同的term。term中包含两部分一部分是文档的域名,另一部分是单词的内容,term是创建索引的关键词对象
2.ElasticSearch简介
2.1什么是ElasticSearch
Elasticsearch,简称es,es是一个开源的高扩展的分布式全文检索系统,它可以近乎实时的存储,检索数据,本身扩展性也好,可以扩展到上百台服务器,处理PB级别的数据,es也使用java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是他的目的是通过简单的RestfulAPI来隐藏Lucene的复杂性,从而让全文搜变得简单
2.2ElasticSerach的使用案例
- 2013年初,GitHub抛弃了Solr,采取ElasticSearch 来做PB级的搜索。 “GitHub使用ElasticSearch搜索20TB的数据,包括13亿文件和1300亿行代码”
- 维基百科:启动以elasticsearch为基础的核心搜索架构
- SoundCloud:“SoundCloud使用ElasticSearch为1.8亿用户提供即时而精准的音乐搜索服务”
- 百度:百度目前广泛使用ElasticSearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部20多个业务线(包括casio、云分析、网盟、预测、文库、直达号、钱包、风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据
- 新浪使用ES 分析处理32亿条实时日志
- 阿里使用ES 构建挖财自己的日志采集和分析体系
2.3ElasticSearch对比Solr
- Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;
- Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式;
- Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供;
- Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于Elasticsearch
3.ElasticSearch相关概念
3.1概述
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而他不仅仅是存储,还会索引每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引,搜索,排序,过滤。Elasticsearch比传统关系型数据库如下:
Relational DB -> Databases -> Tables ->Rows ->Columns
Elasticsearch -> Indices ->Types ->Documents ->Fields
3.2Elasticsearch核心概念
3.2.1 索引index
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引,一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多个索引
3.2.2 类型type
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上分类/分区,其语义完全由你来顶。通常,会为具有一组共享字段的文档定义一个类型,比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中,在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,可以为评论数据定义另一个类型
3.2.3字段field
相当于是数据表的字段,对文档数据根据不同的属性进行的分类标识
3.2.4映射mapping
mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里可以设置的,其他就是处理es里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要考虑如何建立映射才能对性能最好
3.2.5文档document
一个文档是一个可被索引的基础信息党员。比如,你可以拥有么偶一个客户的文档,某一个产品的一个文档,当然,爷可以拥有某个订单的一个文档,文档以JSON格式来表示,而JSON是一个到处存在的互联网数据交互格式
在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引赋予一个索引的type
3.2.6接近实时NRT
Elasticsearch是一个接近实时的搜索平台,这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(一秒内)
3.2.7集群cluster
一个集群就是有一个或多个节点组织在一起,他们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”,这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群
3.2.8节点Node
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群
3.2.9分片和复制shards&replicas
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因: 1)允许你水平分割/扩展你的内容容量。 2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。复制之所以重要,有两个主要原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。
4.Elasticsearch安装
1.docker镜像下载
docker pull elasticsearch:5.6.12
2.创建容器
docker run -d --name=es -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e elasticsearch
9200端口(Web管理平台端口)9300(服务默认端口)
一定要添加jvm内存配置,否则会导致进程卡死
浏览器访问:192.168.232.129:9200
3.开启远程连接
es从5版本后默认不开启远程连接和跨域连接,所以我们需要修改es配置开启,代码如下:
方法1:
进入容器
docker exec -it es /bin/bash
进入config目录
cd config
修改elasticsearch.yml文件
vim elasticsearch.yml
在此之前,需要安装vim编辑器
apt-get update
apt-get install vim
将代码修改如下
方法2:
创建一个存放配置的文件,将容器中的elasticsearch.yml文件复制出来并作方法1一样的修改
docker cp es:/usr/share/elasticsearh/config/elasticsearch.yml ./
vim elasticsearch.yml
将修改好的文件再复制回去,替换之前的文件
docker cp elasticsearch.yml es:/usr/share/elasticsearh/config/elasticsearch.yml
以上两种方法都可,做完之后修改系统参数
vim /etc/sysctl.conf
vm.max_map_count=655360
sysctl -p
所有工作做完后,重启容器
docker restart es
如果想让容器开机启动,则执行如下命令
docker update --restart=always 容器名称
5.ElasticSearch的客户端操作
实际开发中,主要有三种方式可以作为elasticsearch服务的客户端:
- 第一种,elasticsearch-head插件(6版本之后不再支持)
- 第二种,使用elasticsearch提供的Restful接口直接访问
- 第三种,使用elasticsearch提供的API访问
5.1 elasticsearch-head
ElasticSearch不同于Solr自带图形化界面,我们可以通过安装ElasticSearch的head插件,完成图形化界面的效果,完成索引数据的查看。安装插件的方式有两种,在线安装和本地安装。本文档采用本地安装方式进行head插件的安装。elasticsearch-5-*以上版本安装head需要安装node和grunt
node.js的安装就不在赘述,直接安装grunt
在cmd执行如下命令:
cnpm install -g grunt-cli
下载head插件:https://github.com/mobz/elasticsearch-head/tree/v5.0.0
选择下载压缩文件,然后在本地创建目录解压
cmd中进入到该文件目录下,执行如下命令:
>npm install
>grunt server
这里有个特殊问题(如果下载有罗技,需要修改head插件的监听端口,只要不是9100即可,因为与罗技冲突)
打开Gruntfile.js文件,修改配置
打开浏览器查看
5.2使用Postman工具进行Restful接口访问
5.2.1接口语法
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
其中:
参数 | 解释 |
---|---|
VERB | 适当的http方法或谓词:get、post、put、head或者delete |
PROTOCOL | http或者https |
HOST | es集群中任意节点的主机名 |
PORT | 端口号,默认9200 |
PATH | API终端路径(例如_count将返回集群中文档数量)。path可能包含多个组件 |
QUERY_STRTING | 任意可选的查询字符串参数 |
BODY | 一个json格式的请求体 |
5.2.2创建索引index和映射mapping
请求url:
PUT 192.168.232.129:9200/blog1
请求体:
{
"mappings":{
"properties":{
"article":{
"id":{
"type":"long",
"store":true,
"index":"not_analyzed"
},
"title":{
"type":"text",
"store":true,
"index":"analyzed",
"analyze":"standrd"
},
"content":{
"type":"text",
"store":true,
"index":"analyzed",
"anaylzer":"standrd"
}
}
}
}
}
5.2.3创建索引后设置Mapping
我们可以在创建索引时设置mapping信息,当然也可以先创建索引然后设置mapping。
在上一个步骤中不设置mapping信息,直接使用put方法创建一个索引,然后设置mapping信息
请求时的url:
POST http://192.168.232.129:9200/blog2/hello/_mapping
请求体:
{
"hello":{
"properties":{
"id":{
"type":"long",
"store":true
},
"title":{
"type":"text",
"store":true,
"index":true,
"analyzer":"standard"
}
}
}
}
5.2.5删除索引index
请求url:
DELETE 192.168.232.129:9200/blog1
5.2.6修改文档document
POST 192.168.232.129:9200/blog1/article/1
5.2.7删除文档document
DELETE 192.168.232.129:9200/blog1/article/1
5.2.8查询文档-根据id查询
GET 192.168.232.129:9200/blog1/article/1
5.2.9查询文档-querystring查询
POST 192.168.232.129:9200/blog1/article/_search
请求体:
{
"query":{
"query_string":{
"default_field":"title",
"query":"搜索服务器"
}
}
}
5.2.10查询文档-term查询
POST 192.168.232.129:9200/blog1/article/_search
请求体
{
"query":{
"term":{
"title":"搜索"
}
}
}
两种搜索的区别:
querystring搜索关键词分词,而term不分词
6.IK分词器
6.1简介
IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出 了3个大版本。最初,它是以开源项目Lucene为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的IKAnalyzer3.0则发展为 面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。IK分词器3.0的特性如下:
1)采用了特有的“正向迭代最细粒度切分算法“,具有60万字/秒的高速处理能力。 2)采用了多子处理器分析模式,支持:英文字母(IP地址、Email、URL)、数字(日期,常用中文数量词,罗马数字,科学计数法),中文词汇(姓名、地名处理)等分词处理。 3)对中英联合支持不是很好,在这方面的处理比较麻烦.需再做一次查询,同时是支持个人词条的优化的词典存储,更小的内存占用。 4)支持用户词典扩展定义。 5)针对Lucene全文检索优化的查询分析器IKQueryParser;采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。
6.2IK分词器安装
1.下载IK分词器
IK分词器下载地址https://github.com/medcl/elasticsearch-analysis-ik/releases
上传到服务器,解压,改名为ik
unzip elasticsearch-analysis-ik-5.6.12.zip
mv elasticsearch ik
将ik目录拷贝到docker容器的plugins目录下
docker cp ./ik es:/usr/share/elasticsearch/plugins
2.ik分词器测试
访问: http://192.168.232.129:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是程序员
访问: http://192.168.232.129:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是程序员
- ik_max_word:会将文本做最细粒度的拆分
比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共
和国、人民、共和国、大会堂、大会、会堂等词语。
- ik_smart:会做最粗粒度的拆分
比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。
7.kaibana使用-掌握DSL语句
我们上面使用的是elasticsearch-head插件实现数据查找的,但是elasticsearch-head的功能比较单一,我们这里需要一个更专业的工具实现对日志的实时分析,也就是我们接下来要讲的kibana。
Kibana 是一款开源的数据分析和可视化平台,它是 Elastic Stack 成员之一,设计用于和 Elasticsearch协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索、查看、交互操作。您可以很方便的利用图表、表格及地图对数据进行多元化的分析和呈现。
Kibana 可以使大数据通俗易懂。它很简单,基于浏览器的界面便于您快速创建和分享动态数据仪表板来追踪 Elasticsearch 的实时数据变化。
搭建 Kibana 非常简单。您可以分分钟完成 Kibana 的安装并开始探索 Elasticsearch 的索引数据 — 没有代码、不需要额外的基础设施。
7.1安装
1.镜像下载
docker pull docker.io/kibana:5.6.12
2.创建一个kibana容器
docker run -id -e ELASTICSERACH_URL=http://192.168.232.129:9200 --name kibana -p 5601:5601 kibana:5.6.12
ELASTICSEARCH_URL=http://192.168.232.129:9200: 是指链接得es地址
kibana快捷键
ctrl+i 自动缩进
ctrl+enter 提交请求
down 打开自动补全菜单
enter或tab 选中选项自动补全
esc 关闭补全菜单
3.访问测试
7.2Kibana使用
3.2.1配置索引
要使用Kibana,您必须至少配置一个索引。索引用于标识Elasticsearch索引以运行搜索和分析。他还用于配置字段。
我们修改索引名称的匹配方式即可,下面两个选项不用勾选。点击create,会展示出当前配置的索引的域信息
7.3.2数据搜索
discover为数据搜索部分,可以对日志信息进行搜索操作。
7.3.3DSL语句使用
Query DSL是一个java开源框架用于构建类型安全的SQL查询语句,采用API代替传统的拼接字符串来构造查询语句,目前query DSL支持的平台包括JPA,JDO,SQL,Java Collections,RDF,Lucene,Hibernate Search。elasticsearch提供了一套完整基于JSON的DSL语言来定义查询
索引操作:
1.查询所有索引
GET /_cat/indices?v
2.删除某个索引
DELETE /skuinfo
3.新增索引
PUT /user
4.创建映射
PUT /user/userinfo/_mapping
{
"properties":{
"name":{
"type":"text",
"analyzer":"ik_smart",
"search_analyzer":"ik_smart"
},
"city":{
"type":"text",
"analyzer":"ik_smart",
"search_anaylzer":"ik_smart"
},
"age":{
"type":"long"
},
"description":{
"type":"text",
"analyzer":"ik_smart",
"search_analyzer":"ik_smart"
}
}
}
5.增加文档数据
PUT /user/userinfo/1
{
"name":"李四",
"age":22,
"city":"深圳",
"description":"李四来自湖北武汉"
}
6.修改数据
a.替换操作
更新数据可以使用之前的增加操作,这种操作会将整个数据替换掉,代码如下:
PUT /user/userinfo/4
{
"name":"张三丰",
"description":"在武汉读书,在深圳工作"
}
b.更新操作
POST /user/userinfo/4/_update
{
"doc":{
"name":"张三丰",
"description":"在武汉读书,家在武汉,在深圳工作!"
}
}
7.删除document
DELETE user/userinfo/7
数据查询
1.查询所有数据
GET /user/_search
2.根据id查询
GET /user/userinfo/2
3.sort排序
GET /user/_search
{
"query":{
"match_all":{}
},
"sort":{
"age":{
"order":"desc"
}
}
}
4.分页
GET /user/_search
{
"query":{
"match_all":{}
},
"sort":{
"age":{
"order":"desc"
}
},
"from":0,
"size":2
}
解释:
from:从下N条记录开始查询
size:每页显示条数
查询模式:
1.term查询
term主要用于分词精确匹配,如字符串、数值、日期等(不适合情况:1.列中除英文字符外有其它值 2.字符串值中有冒号或中文 3.系统自带属性如_version)
GET _search
{
"query":{
"term":{
"city":"武汉"
}
}
}
2.terms查询,可以指定多个匹配条件
8.Elasticsearch编程操作
8.1.创建工程,导入坐标
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.12</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.12</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
8.2.创建索引index
//创建索引
@Test
public void test1()throws Exception{
//创建client对象
Settings settings = Settings.builder().put("cluster.name","my-elasticsearch").build();
TransportClient client =new PreBuiltTransportClient(settings).addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("192.168.232.129"),9300)
);
//创建名称为blog2的索引
client.admin().indices().prepareCreate("blog2").get();
client.close();
}
8.3.创建映射mapping
//创建映射
public void test2()throws Exception{
//创建client对象
Settings settings = Settings.builder().put("cluster.name","my-elasticsearch").build();
TransportClient client =new PreBuiltTransportClient(settings).addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("192.168.232.129"),9300)
);
//添加映射
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.startObject("article")
.startObject("properties")
.startObject("id")
.field("type", "integer").field("store", "yes")
.endObject()
.startObject("title")
.field("type", "string").field("store", "yes").field("analyzer", "ik_smart")
.endObject()
.startObject("content")
.field("type", "string").field("store", "yes").field("analyzer", "ik_smart")
.endObject()
.endObject()
.endObject()
.endObject();
// 创建映射
PutMappingRequest mapping = Requests.putMappingRequest("blog2")
.type("article").source(builder);
client.admin().indices().putMapping(mapping).get();
//释放资源
client.close();
8.4.建立文档document(XContentBuilder)
@Test
public void testAddDocument() throws Exception{
//创建一个client对象
Settings settings = Settings.builder().put("cluster.name","my-elasticsearch").build();
TransportClient client =new PreBuiltTransportClient(settings).addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("192.168.232.129"),9300)
);
//创建一个文档对象
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("id",21)
.field("title","北方入秋速度明显加快,多地降温幅度最多可达10度")
.field("content","阿联酋一架客机在纽约机场被隔离 10名乘客病倒")
.endObject();
client.prepareIndex()
.setIndex("blog2")
.setType("article")
.setId("2")
.setSource(builder)
.get();
client.close();
}
8.5建立文档(使用jackson转换实体)
创建Article实体
public class Article{
private Integer id;
private String title;
private String content;
}
添加依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.1</version>
</dependency>
3.代码实现
@Test
public void testAddDocument2() throws Exception {
//创建一个Article对象
Article article = new Article();
//设置对象的属性
article.setId(3l); article.setTitle("MH370坠毁在柬埔寨密林?中国一公司调十颗卫星去拍摄"); article.setContent("警惕荒唐的死亡游戏!俄15岁少年输掉游戏后用电锯自杀");
//把article对象转换成json格式的字符串。
ObjectMapper objectMapper = new ObjectMapper();
String jsonDocument = objectMapper.writeValueAsString(article);
System.out.println(jsonDocument);
//使用client对象把文档写入索引库
client.prepareIndex("index_hello","article", "3").setSource(jsonDocument, XContentType.JSON) .get();
//关闭客户端
client.close();
}
8.6.查询文档操作
8.6.1termQuery
@Test
public void testQueryByTerm()throws Exception{
//创建一个client对象
Settings settings = Settings.builder().put("cluster.name","my-elasticsearch").build();
TransportClient client =new PreBuiltTransportClient(settings).addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("192.168.232.129"),9300)
);
//创建一个QueryBuilder对象
//参数1:要搜索的字段
//参数2:要搜索的关键字
QueryBuilder queryBuilder = QueryBuilders.termQuery("title","美丽的护士");
//执行查询
SearchResponse searchResponse = client.prepareSearch("blog2")
.setTypes("article")
.setQuery(queryBuilder)
.get();
//去查询结果
SearchHits searchHits = searchResponse.getHits();
//去查询结果的总记录数
System.out.println("查询结果总记录数:"+searchHits.getTotalHits());
//查询结果列表
Iterator<SearchHit> iterator = searchHits.iterator();
while (iterator.hasNext()){
SearchHit searchHit = iterator.next();
//打印文档对象,以json格式输出。
System.out.println(searchHit.getSourceAsString());
//取得文档属性
System.out.println("文档属性");
Map<String,Object> document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
}
8.6.2QueryString
@Test
public void testQueryByQueryString() throws Exception {
//创建一个QueryBuilder对象
//参数1:要搜索的字段
//参数2:要搜索的关键词
QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("美丽的女护 士").defaultField("title");
//执行查询
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
//取查询结果
SearchHits searchHits = searchResponse.getHits();
//取查询结果的总记录数
System.out.println("查询结果总记录数:" + searchHits.getTotalHits());
//查询结果列表
Iterator<SearchHit> iterator = searchHits.iterator();
while(iterator.hasNext()) {
SearchHit searchHit = iterator.next();
//打印文档对象,以json格式输出
System.out.println(searchHit.getSourceAsString());
//取文档的属性
System.out.println("-----------文档的属性");
Map<String, Object> document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
//关闭client
client.close();
}
8.6.3Match
@Test
public void testQueryByMatchQuery() throws Exception {
//创建一个QueryBuilder对象
//参数1:要搜索的字段
//参数2:要搜索的关键词
QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "美丽的女护士");
//执行查询
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
//取查询结果
SearchHits searchHits = searchResponse.getHits();
//取查询结果的总记录数
System.out.println("查询结果总记录数:" + searchHits.getTotalHits());
//查询结果列表
Iterator<SearchHit> iterator = searchHits.iterator();
while(iterator.hasNext()) {
SearchHit searchHit = iterator.next();
//打印文档对象,以json格式输出
System.out.println(searchHit.getSourceAsString());
//取文档的属性
System.out.println("-----------文档的属性");
Map<String, Object> document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content")); }
//关闭client
client.close();
}
8.6.4查询文档分页
@Test
private void search(QueryBuilder queryBuilder) throws Exception {
//创建一个client对象
Settings settings = Settings.builder().put("cluster.name","my-elasticsearch").build();
TransportClient client =new PreBuiltTransportClient(settings).addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("192.168.232.129"),9300)
);
//执行查询
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
//设置分页信息
.setFrom(0)
//每页显示的行数
.setSize(5).get();
//取查询结果
SearchHits searchHits = searchResponse.getHits();
//取查询结果的总记录数
System.out.println("查询结果总记录数:" + searchHits.getTotalHits());
//查询结果列表
Iterator<SearchHit> iterator = searchHits.iterator();
while(iterator.hasNext()) {
SearchHit searchHit = iterator.next();
//打印文档对象,以json格式输出
System.out.println(searchHit.getSourceAsString());
//取文档的属性
System.out.println("-----------文档的属性");
Map<String, Object> document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
//关闭client
client.close();
}
epareSearch(“index_hello”)
.setTypes(“article”)
.setQuery(queryBuilder)
//设置分页信息
.setFrom(0)
//每页显示的行数
.setSize(5).get();
//取查询结果
SearchHits searchHits = searchResponse.getHits();
//取查询结果的总记录数
System.out.println(“查询结果总记录数:” + searchHits.getTotalHits());
//查询结果列表
Iterator iterator = searchHits.iterator();
while(iterator.hasNext()) {
SearchHit searchHit = iterator.next();
//打印文档对象,以json格式输出
System.out.println(searchHit.getSourceAsString());
//取文档的属性
System.out.println("-----------文档的属性");
Map<String, Object> document = searchHit.getSource();
System.out.println(document.get(“id”));
System.out.println(document.get(“title”));
System.out.println(document.get(“content”));
}
//关闭client
client.close();
}