本篇博客将带你深入探索Elasticsearch,从入门到精通。我们将引导你了解Elasticsearch的基本概念,学习如何建立索引、执行搜索和聚合操作,以及高级技巧,帮助你成为一名Elasticsearch专家。
Elasticsearch是一个强大的分布式搜索和分析引擎,被广泛用于全文搜索、日志分析、数据挖掘等领域。无论你是初学者还是有经验的开发者,本文都将从基础知识开始,逐步引导你进入Elasticsearch的世界,掌握从入门到精通的技能。
1>什么是ElasticSearch?
ElaticSearch,简称es,es是一个开源的搞扩展的分布式全文检索引擎,它可以近乎实时的存储,检索数据.本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据.es也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单
ElasticSearch是一个基于Lucene搜索服务器它提供了一个分布式多功能多用户能力的全文搜索引擎,基于RESTful web接口 ElasticSearch是用Java开发的,并作为Apache许可条款下的开放源码发布的,是当前流行的企业级搜索引擎,设计用于云计算中能够达到实时搜索,稳定,可靠,快速,安装使用方便
我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作非常困难的我们希望搜解决方案要运行速度快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够与简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够与从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案,·因此我们利用ElasticSearch来解决所有这些问题及可能出现的更多其他问题
2>ElasticSearch的使用案例
·2013年初,GitHub抛弃了Solr,采取ElstaicSearch来做PB级的搜索,GitHub使用ElasticSearch搜索20TB的数据包括13亿文件和1300亿行代码
·维基百科:启动以ElasticSearch为基础的核心搜索架构
·SoundClod:SoundCloud使用ElasticSearch为1.8亿用户提供及时而精准的音乐搜索服务
·百度:百度目前广泛使用ElasticSearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常,目前覆盖百度内部20多个业务线(包括casio,云分析,网萌,预测,文库,直达号,钱包,风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据
·新浪使用ES分析处理32亿实时日志
·阿里使用ES构建挖财自己的日志采集和分析体系
3>ElasticSearch对比Solr
·Solr利用Zookeeper进行分布式管理,而ElasticSearch自带有分布式协调管理功能
·Solr支持更多格式的数据,而ElasticSearch仅只支持json文件格式
·Solr官方提供的功能更多,而ElasticSearch本身更注重于核心功能,高级功能多由第三方插件来提供
·Solr在传统的搜索应用中变现好于ElasticSearch但在处理实时搜索应用时效率明显低于ElasticSearch
ElasticSearch的总结:
1.ElasticSearch是一个机遇Lucene的搞扩展的分布式搜索服务器支持开箱使用
2.ElasticSearch隐藏了Lucene的复杂性,对外提供Restful接口来操作索引,搜索
ElasticSearch的优点
1.扩展性好,可部署上百台服务器集群,处理PB级别的数据
2.近实时的去索引数据,搜索数据
关于ElasticSearch和Solr的选择
1.公司使用Solr可以满足现在需求就不需要更换了
2.公司准备进行全文检索项目的开发,建议优先考虑ElasticSearch,因为像GitHub这样大规模都在使用
1>.索引结构
下面是ElasticSearch的索引结构,下边黑色的部分是物理结构,上边黄色的部分是逻辑结构,逻辑结构也是为了更好的去描述ElasticSearch的工作原理及去使用物理结构中的索引文件
|---------------------------------------------------------|
| | index索引 | |
| —————————————————————————————————————————————————— |
| | 分词列表 | |
| | term term term term term term term ... | |
| —————————————————————————————————————————————————— |
| ___________________________________________________ |
| | Doucument文档 | |
| | document document document | |
| | filed1,field2 filed1,field2 filed1,field2 | |
| ___________________________________________________ |
|----------------------------------------------------------|
————————————————————————————————————————————————————————————
| 索引文件 |
————————————————————————————————————————————————————————————
2>.逻辑结构部分是一个倒序索引表:
1.将要搜索的文档内容分词,所有不重复的词组成分词列表
2.将搜索的文档最终以Doucument方式存储起来
3.每个词和Document都有关联
如下
Trem Doc_1 Doc_3
-------------------------------
Quick X
The X
Brown X X
-------------------------------
现在,如果我们想搜索quick brown,我们只需要找包含每个词条的文档
Trem Doc_1 Doc_3
-------------------------------
Quick X
Brown X X
-------------------------------
Total 2 1
两个文档都匹配,但是第一个文档比第二个文档匹配度更高。如果我们使用仅计算匹配词条数量的简单相似性算法,那么我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳
3>.RESTful应用方法
如何使用ES?
ElasticSearch提供RESTful API接口进行索引,搜索,并且支持多种客户端
ES的应用方式
1).用户在前端搜索关键字
2).项目前端通过Http方式请求项目服务端
3).项目服务端通过Http RESTful方式请求ES集群记性搜索
4).ES集群从索引库检查索引
1>安装配置:
1、新版本要求至少jdk1.8以上。
2、支持tar、zip、rpm等多种安装方式。 在windows下开发建议使用ZIP安装方式。
3、支持docker方式安装
详细参见:https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html
下载ES: Elasticsearch 6.2.1
https://www.elastic.co/downloads/past-releases
解压 elasticsearch-6.2.1.zip
bin:脚本目录包括:启动、停止等可执行脚本
config:配置文件目录
data:索引目录,存放索引文件的地方
logs:日志目录
modules:模块目录,包括了es的功能模块
plugins:插件目录,es支持插件机制
2>.配置文件
1).三个配置文件
ES的配置文件的地址根据安装形式的不同而不同:
使用zip、tar安装,,配置文件的地址在安装目录的config下.
使用RPM安装,配置文件在/etc/elasticsearch下.
使用MSI安装,配置文件的地址在安装目录的config下,并且会自动将config目录地址写入环境变量 ES_PATH_CONF
ElasticSearch是面向文档的,这意味着它可以存储整个对象或文档然而它不仅仅是存储,还会索引每个文档的内容使之可以被搜索.在ElasticSearch中,可以对文档(而非成行成列的数据)进行索引,搜索,排序,过滤,ElasticSearch比传统关系型数据库如下:
Relational DB-->Databases-->Tables-->Rows-->Colunm
ElasticSearch-->Indices-->Types-->Document-->Field
1>.ElasticSearch核心概念
1).索引index
一个索引就是一个拥有几分相似特征的文档的集合,比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引一个索引由一个名字来表示(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引,搜索,删除,更新的时候,都要使用这个名字,在一个集群中,可以定义任意多的索引
2).类型type
在一个索引中你可以定义一种或多种类型,一个类型是你的索引的一个逻辑上的分类/分区器语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型比如说,我们假设你运营了一个博客平台并且把你所有的数据存储到一个索引中,在这个索引中,你可以为用户定义一个类型,为博客数据指定另一个类型,当然也可以为评论数据指定另一个类型
3).字段Field
相当于是数据表的字段,对文档数据根据不同属性进行分类的标识
4).映射Mapper
mapping是处理数据的方式或规则方面做一些限制,如某个字段的数据类型,默认值,分析器,是否被索引等等这些都是映射里面可以设置的,其他就是处理es里面数据的一些使用规则设置也叫作映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考和如何建立映射才能对性能更好
5).文档document
一个文档是一个可被索引的基础单元信息,比如你可以拥有某一个客户的文档,某一个产品的文档,当然你也可以拥有某个订单的文档,文档以JSON格式来表示,而JSON是一个到处存在的互联网数据交互格式
在一个index/type里面,你可以存储任意多的文档,注意尽管一个文档,物理上存储在于一个索引之中,文档必须被索引/赋予一个索引的type
6).接近实时NRT
ElasticSearch是一个接近实时的搜索平台,这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1s以内)
7).集群cluster
一个集群就是由一个或者多个节点组织在一起,他们共同持有整个的数据,并一起提供索引和搜索功能.一个集群由一个唯一的名字表示,这个名字默认是"elasticsearch",这个名字是重要的,因为一个节点只能通过某个指定集群的名字,来加入这个集群
8).节点node
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能.和集群类似,一个节点也是由一个名字来标识的,默认情况下这个名字是一个随机的 漫威漫画角色的名字,这个名字会在启动的时候赋予节点这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你回去确定网络中的哪些服务器对应于ElasticSearch集群中的哪些节点
一个节点可以通过配置集群名称的方式来加入一个指定的集群,默认情况下每个节点都会被安排加入到一个叫做"elasticsearch"的集群中,这意味着如果你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动形成并加入到一个叫做"elasticsearch"的集群中
在一个集群里,只要你想,可以拥有任意多个节点,而且如果当前你的网络中没有ElasticSearch的节点,这时启动一个节点会默认创建并加入一个叫做"elasticsearch"的集群
1>.使用PostMan来创建索引库
Postman的请求地址:http://localhost:9200/blog
***PUT请求***
选择Body-->raw-->JSON(application/json)
请求体:
{
"mappings":{
"article":{
"properties":{
"id":{
"type":"long",
"store":true
},
"title":{
"type":"text",
"store":true,
"index":true,
"analyzer":"standard"
},
"content":{
"type":"text",
"store":true,
"index":true,
"analyzer":"standard"
}
}
}
}
}
2>.使用Postman设置mapping映射
Postman的请求地址:http://localhost:9200/blog/hello_mapping
***POST****
请求体:
{
"hello":{
"id":{
"type":"long",
"store":true
},
"title":{
"type":"text",
"store":true,
"index":true,
"analyzer":"standard"
},
"content":{
"type":"text",
"store":true,
"index":true,
"analyzer":"standard"
}
}
}
3>.删除索引库
在elasticsearch-head中点击动作-->删除--->输入"删除"即可
使用Postman来删除索引库
Postman的请求地址:http://localhost:9200/blog
***DELETE***
请求体:有没有都无所谓
4>.使用Postman在索引库中添加文档(Document)
Postman的请求地址:http://localhost:9200/blog/article/1
***POST*** 当前的1是索引库中的_id不指定默认生成类似UUID的唯一
请求体:
{
"id":1,
"title":"新添加的数据",
"content":"完全地表情我漆黑的晚点去浦东区无给当前我大哥"
}
5>.使用Postman在索引库中删除文档(Doucument)
Postman的请求地址:http://localhost:9200/blog/article/1
***DELETE***
同样可以使用head来删除
6>.使用Postman在索引库中修改文档(Document)
底层是用Lucene实现所以更新的原理是相同的先添加后删除
Postman的请求地址:http://localhost:9200/blog/article/1
***POST***
--两次操作添加后删除
请求体:
{
"id":1,
"title":"修改之后的文档",
"content":"去大群无请问强无敌强无敌强无敌强无敌请问"
}
7>.使用Postman在索引库中查询文档(Document--根据ID查询)
Postman的请求地址:http://localhost:9200/blog/article/1
***GET***
请求体:NULL
8>.使用Postman在索引库中查询文档(Document--根据关键词查询)
Postman的请求地址:http://localhost:9200/blog/article/_search
***POST***
请求体:
{
"query":{
"term":{
"title":"修"
}
}
}
注意:使用的是标准分析器,分析中文的话只能一个字一个字进行查询
8>.使用Postman在索引库中查询文档(Document--根据queryString查询)
Postman的请求地址:http://localhost:9200/blog/article/_search
***POST***
请求体:
{
"query":{
"query_string":{
"default_field":"title",
"query":"今天修改了"
}
}
}
default_field:默认搜索域
query:查询条件
先使用分析器进行分词然后再进行查询
9>使用head插件来查询索引库
使用基本查询:
条件选项:
must:必须满足
must_not:必须满足
should:应该满足
match_all:查询所有
1>.上述查询存在的问题(使用的是默认的分词器)
在进行字符串查询时,我们发现去搜索"搜索服务器"和"钢索"都可以搜索到数据而在进行词条查询的时候,我们搜索"搜索"却没有得到数据原因就是ElasticSearch的标准分词器导致的,的那个我们创建索引的时候字段使用的就是默认的分词器
{
"hello"{
"content":{
"type":"text",
"store":true,
"index":true,
"analyzer":"standard"//标准分词器
}
}
}
使用Postman来查看标准分词器的分词结果
请求地址:http://localhost:9200/_analyze
***POST***
请求体:
{
"text":"测试分词器,后边是测试内容"
}
分词结果:
{
"tokens": [
{
"token": "测",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "试",
"start_offset": 1,
"end_offset": 2,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "分",
"start_offset": 2,
"end_offset": 3,
"type": "<IDEOGRAPHIC>",
"position": 2
}
}
1>.测试分词器
在添加文档时会进行分词,索引中存放的就是一个一个的词(term),当你去搜索时就是拿关键字去匹配词,最终找到词关联的文档
测试当前索引库使用的分词器:
Postman请求地址:http://localhost:9200/_analyze
***POST****
请求体
{"text":"测试分词器"}
结果:没有使用中文分词器所以分词汉字的话是一个一个的
2>安装IK分词器
下载IK分词器(Github地址:"https://github.com/medcl/elasticsearch-analysis-ik)
解压,并将解压的文件拷贝到ES安装目录的plugins下的ik目录下
测试分词效果:
Postman请求地址:http://localhost:9200/_analyze
{"text":"后边的是测试内容","analyzer":""}
3>.两种分词模式
ik分词器有两种分词模式:ik_max_word和ik_smart模式
1.ik_max_word
会将文本做最细粒度的拆分,比如会将"小猫吃鱼"拆分为"小猫,吃鱼,会等"
2.ik_smart
会做最粗粒度的拆分,比如会将"小猫吃鱼"拆分为小猫,,,,吃鱼
测试两种分词模式:
Postman请求地址:http://localhost:9200/_analyze
***POST***
请求体:
{"text":"小猫","analyzer":"ik_smart"}
ES集群是一个P2P类型(使用gossip协议)的分布式系统,除了集群状态管理以外,其他所有的请求都可以发送到集群内热议一台节点上,这个节点可以自己找需要转发哪些节点,并且直接跟这些节点通信.所以,从网络架构及配置服务上来说,构建集群所需要的配置极其简单.在ElasticSearch2.0之前,无阻碍的网络下,所有配置了相同的cluster.name的节点都自动归属到一个集群.2.0版本之后基于安全的考虑避免开发环境过于随便造成的麻烦,从2.0版本开始,默认的自动发现方式改为了单播(unicast)方式.配置里提供几台节点的地址,ES将其视作gossip router角色,借以完成集群的发现.由于这只是ES内一个很小的功能,所以gossip router角色并不需要单独配置,每个ES节点都可以担任,所以采用单播方式的集群,各节点都配置相同的几个节点列表作为router即可
集群中没有数量的限制,一般大于等于两个节点就可以看作是集群了.一般处于高性能及高可用方面来考虑一般集群中的节点数量都是3个或者是3个以上
1>.集群相关的概念
集群(Cluster)
一个集群就是由一个或者多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能.一个集群由一个唯一的名字表示,这个名字默认就是:"elasticsearch"这个名字是重要的,因为一个节点只能通过某个集群的名字来加入这个集群
节点(Node)
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能.和集群类似,一个节点也是由一个名字来标识的,默认情况下这个名字是一个随机的 漫威漫画角色的名字,这个名字会在启动的时候赋予节点这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你回去确定网络中的哪些服务器对应于ElasticSearch集群中的哪些节点
一个节点可以通过配置集群名称的方式来加入一个指定的集群,默认情况下每个节点都会被安排加入到一个叫做"elasticsearch"的集群中,这意味着如果你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动形成并加入到一个叫做"elasticsearch"的集群中
在一个集群里,只要你想,可以拥有任意多个节点,而且如果当前你的网络中没有ElasticSearch的节点,这时启动一个节点会默认创建并加入一个叫做"elasticsearch"的集群
分片和复制(shards&replicas)
一个索引可以存储超出单个节点硬件限制的大量数据.比如,一个具有10亿文档的索引占据了1TB的磁盘空间,而任一个节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢为了解决这个问题,ElasticSearch提供了将索引划分成多份的能力,这些份就叫做分片当你创建一个索引的时候,你可以指定你想要的分片的数量.每个分片本身也是一个功能完善并且独立的"索引",这个索引可以被放置到集群的任何节点上,分片很重要主要有两方面的原因:
1.允许你水平分隔/扩展你的内容容量
2.允许你在分片(潜在地,位于多个节点上)之上进行分布式的,并行的操,进而提高性能/吞吐量
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由ElasticSearch管理的,对于作为用户的你来说,这些都是透明的
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了这种情况下,有一个故障转移机制是非常有用并且强烈推荐的.为此目的,ElasticSearch允许你创建分片的一份或者多份拷贝这些拷贝叫做复制分片,或者直接叫做复制
复制之所以重要,有两个原因:在分片/节点失败的情况下,提供了高可用性因为这个原因,注意到复制分片从不与原/主要(Original/Primary)分片置于同一节点上是非常重要的扩展你的搜索量/吞吐量,因为搜索可以在索索的复制上并行运行,总之,每个索引可以被分成多个分片.一个索引也可以被复制0次(就是没有被复制)或多次,一旦复制了,每个索引就有看主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别,分片和复制的数量可以在索引创建的时候指定.在索引创建之后你可以在任何时候动态的改变复制的数据,但是你时候不能改变分片的数量
默认情况下,ElasticSearch中的每个索引被分成5个主分片和一个复制,如果你的集群中至少有两个节点,你的索引会有5个主分片和另外5个复制分片(一个完全拷贝)这样的话每个索引总共就有10个分片
物理存储单元:一个物理的存储单元就是一个Lucene创建的索引库
2>关于集群的搭建
在本机上创建三个不同的ElasticSearch节点
删除data文件夹并且修改elasticsearch.yml文件
http.cors.enabled: true
http.cors.allow-origin: "*"
#节点1的配置信息
#集群名称保证唯一
cluster.name: my-elasticsearch
#节点名称必须不一样
node.name: node3
#必须为本机的ip地址
network.host: 127.0.0.1
#服务器端口号,在同一台机器下必须不一样
http.port: 9203
#集群间通信端口号,在同一台机器下必须不一样
transport.tcp.port: 9303
#设置集群自动发现机器ip集合
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9301", "127.0.0.1:9302","127.0.0.1:9303"]
设置Maven的编译级别
<properties>
<maven.compiler.source>1.9</maven.compiler.source>
<maven.compiler.target>1.9</maven.compiler.target>
</properties>
1>.使用java客户端来管理ES/创建ES索引库
1).创建索引库
创建一个java工程
添加jar包,添加maven坐标
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.27</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.27</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
编写测试方法实现创建索引
@Test
public void testCreateIndex()throws Exception{
//1.创建一个Settings对象,相当于是一个配置信息,主要配置集群的名
Settings settings=Settings.builder().put("cluster.name","my-elasticsearch").build();
//2.创建一个客户端Client对象
TransportClient client=new PreBuiltTransportClient(settings);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9301));
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9302));
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9303));
//3.使用Client对象创建一个索引库
client.admin().indices().prepareCreate("es_hello").get();
//4.关闭Client对象
client.close();
}
2>使用Java客户端来设置Mappings
步骤:
@Test
public void testMapping()throws Exception{
//1).创建Settings对象
Settings settings=Settings.builder().put("cluster.name","my-elasticsearch").build();
//2).创建一个Client对象
TransportClient transportClient=new PreBuiltTransportClient(settings);
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9301));
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9302));
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9303));
//创建一个mappings信息
//3).创建一个mappings信息,应该是json数据,可以是json字符串也可以是XContextBuilder对象
XContentBuilder xContentBuilder= XContentFactory.jsonBuilder().
startObject()
.startObject("hello")
.startObject("properties")
.startObject("id")
.field("type","long")
.field("store",true)
.endObject()
.startObject("title")
.field("type","text")
.field("store",true)
.field("analyzer","ik_smart")
.endObject()
.startObject("content")
.field("type","text")
.field("store",true)
.field("analyzer","ik_smart")
.endObject()
.endObject()
.endObject()
.endObject();
//4).使用Client向ES服务器发送mapping信息
//设置要做映射的索引;preparePutMapping
//设置要做映射的Type:setType
//Mappings信息可以是XContentBuilder对象也可以是JSON格式的字符串 setSource
transportClient.admin().indices().preparePutMapping("es_hello").setType("hello").setSource(xContentBuilder).get();
//5).关闭Client对象
transportClient.close();
}
3>使用Java客户端向索引库中添加文档(XContentBuilder)
private TransportClient client;
@Before
public void init()throws Exception{
Settings settings=Settings.builder().put("cluster.name","myelasticsearch").build();
client=new PreBuiltTransportClient(settings);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9301));
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9302));
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9303));
}
@Test
public void testAddDocument() throws IOException {
//创建一个client对象
//创建一个文档对象
XContentBuilder builder= XContentFactory.jsonBuilder()
.startObject()
.field("id",1l)
.field("title","测试")
.field("content","当前,各种小猫正在为实现...")
.endObject();
//把文档对象添加到索引库
client.prepareIndex().setIndex("es_hello").setType("hello").setId("1").setSource(builder).get();
client.close();
}
4>使用Java向索引库中添加文档(JACKSON)
@Test
public void testAddDocument2()throws Exception{
//创建一个Article
Hello hello=new Hello();
//设置对象的属性
hello.setId(2l);
hello.setTitle("从此刻,向未来——行动宣传片正式发布");
hello.setContent("你见过什么样的?\n" +
"\n" +
"翻天覆地、沧海桑田?\n" +
"\n" +
"潮涌东方、风起云天?\n" +
"\n" +
"你还见过什么样的?");
//把hello对象转换为json格式的字符串
ObjectMapper objectMapper=new ObjectMapper();
String jsonDocument=objectMapper.writeValueAsString(hello);
System.out.println(jsonDocument);
//使用client对象把文档写入索引库
client.prepareIndex("es_hello","hello","2").setSource(jsonDocument, XContentType.JSON).get();
//关闭客户端
client.close();
}
6>索引库的查询(根据id查询)
private void search(QueryBuilder queryBuilder)throws Exception{
//执行查询
SearchResponse searchResponse=client.prepareSearch("es_hello").setTypes("hello").setQuery(queryBuilder).get();
//取出查询结果
SearchHits searchHits=searchResponse.getHits();
//取查询结果的总记录数
System.out.println("查询结果的总记录数:"+searchHits.getTotalHits());
//查询结果列表
Iterator<SearchHit> iterator = searchHits.iterator();
while(iterator.hasNext()){
SearchHit searchHitFields=iterator.next();
//打印文档对象,以JSON格式输出
// System.out.println(searchHitFields.getSourceAsString());
System.out.println("-------------文档的属性");
Map<String, Object> document =searchHitFields.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
//关闭Client对象
client.close();
}
@Test
public void testSearchById()throws Exception{
//创建一个client对象
//创建一个查询对象
QueryBuilder queryBuilder= QueryBuilders.idsQuery().addIds("1","2");
search(queryBuilder);
}
7>.索引库的查询根据term查询
@Test
public void testSearchByTerm()throws Exception{
//创建一个QueryBuilder对象
//name:要搜索的字段/域
//value:要搜索的关键词
QueryBuilder queryBuilder=QueryBuilders.termQuery("title","武国");
search(queryBuilder);
}
8>.根据queryString查询
@Test
public void testQueryString()throws Exception{
QueryBuilder querybuilder=QueryBuilders.queryStringQuery("遥远的东方有一条龙").defaultField("title");
search(querybuilder);
}
1>.分页的处理
在client对象执行查询之前,设置分页信息
然后再执行查询
SearchResponse searchResponse=client.prepareSearch("es_hello").setType("hello").setQuery(queryBuilder).setFrom(0).setSize(5).get();
分页需要设置两个值,一个from,size
from起始的行号,从0开始
size:每页显示的记录数
2>.查询结果高亮显示
(1).高亮的配置
1).设置高亮显示的字段
2).设置高亮显示的前缀
3).设置高亮显示的后缀
(2).在client对象执行查询之前,设置高亮显示的信息
(3).遍历结果列表表明可以从结果中取高亮的结果
private void search1(QueryBuilder queryBuilder,String highlightField)throws Exception{
//执行查询
HighlightBuilder highlightBuilder=new HighlightBuilder();
highlightBuilder.field(highlightField);
highlightBuilder.preTags("<em>");
highlightBuilder.postTags("</em>");
SearchResponse searchResponse=client.prepareSearch("es_hello").setTypes("hello").setQuery(queryBuilder)
//设置分页的信息
.setFrom(0)
//每页显示的条数
//设置高亮信息
.highlighter(highlightBuilder)
.setSize(5).get();
//取出查询结果
SearchHits searchHits=searchResponse.getHits();
//取查询结果的总记录数
System.out.println("查询结果的总记录数:"+searchHits.getTotalHits());
//查询结果列表
Iterator<SearchHit> iterator = searchHits.iterator();
while(iterator.hasNext()){
SearchHit searchHitFields=iterator.next();
//打印文档对象,以JSON格式输出
// System.out.println(searchHitFields.getSourceAsString());
System.out.println("-------------文档的属性");
Map<String, Object> document =searchHitFields.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
System.out.println("---------------------");
System.out.println("********************高亮结果");
Map<String, HighlightField> highlightFields = searchHitFields.getHighlightFields();
System.out.println(highlightFields);
//取出高亮显示的结果
HighlightField highlightField1 = highlightFields.get(highlightField);
Text[] fragments = highlightField1.getFragments();
if (fragments!=null){
String content = fragments[0].toString();
System.out.println(content);
}
}
//关闭Client对象
client.close();
}
1>.Spring Data ElasticSearch简介
什么是Spring Data?
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务Spring Data可以极大的简化JPA的写法,可以在不同的情况下,实现对数据的访问和操作,除了CURD外,还包括分页,排序等一些功能
2>搭建工程
创建Java工程--导入Maven坐标--->编写配置文件
1).Maven坐标:
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version> 2.12.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version> 1.7.27</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>
<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.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version> 2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.0.5.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
2).applicationContent.xml文件的编写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
">
<!--客户端对象的配置-->
<elasticsearch:transport-client id="esClient" cluster-name="my-elasticsearch"
cluster-nodes="127.0.0.1:9301,127.0.0.1:9302,127.0.0.1:9303">
</elasticsearch:transport-client>
<!--配置包扫描器 扫描Dao的接口-->
<elasticsearch:repositories base-package="cn.itxu.es.repository"></elasticsearch:repositories>
<!--配置ElasticSearch模板对象-->
<bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="esClient"></constructor-arg>
</bean>
</beans>
3>.管理索引库
通过本篇博客,你将逐步学习Elasticsearch的各个方面,从基础概念到高级技巧,从入门到精通。掌握Elasticsearch的知识和技能,将有助于你更好地应对各种数据处理和搜索挑战,成为一名Elasticsearch的专家。