ElasticSearch全文搜索引擎

一.全文搜索Lucene入门

1.全文搜索概述

1.1.什么是全文检索

狭义的理解主要针对文本数据的搜索。数据可分为“结构化”数据(关系数据库表形式管理的数据),半结构化数据(XML文档、JSON文档),和非结构化数据(WORD、PDF),通常而言在结构化的数据中搜索性能是比较高的,全文搜索的目的就是把非结构化的数据变成有结构化的数据进行搜索,从而提高搜索效率。

全文搜索引擎 : 就是把没有结构的数据,转换为有结构的数据,来加快对文本的快速搜索,通常而言,有结构的数据的查询是很快的,比如: 有序数组 , 红黑树

1.2.为什么要使用全文搜索
  • 搜索效率高,是like无法比拟的

  • 相关度最高的排在最前面,官网中相关的网页排在最前面; java

  • 关键词的高亮。

  • 只处理文本,不处理语义。 以单词方式进行搜索,比如在输入框中输入“中国的首都在哪里”,搜索引擎不会以对话的形式告诉你“在北京”,而仅仅是列出包含了搜索关键字的网页。

1.3.常见的全文搜索
  • 全文搜索工具包-Lucene(核心)

  • 全文搜索服务器 ,Elastic Search(ES) / Solr等封装了lucene并扩展

2.Lucene概述

2.1.什么是Lucene

Lucene是apache下的一个开源的全文检索引擎工具包(一堆jar包)。它为软件开发人员提供一个简单易用的工具包(类库),以方便的在小型目标系统中实现全文检索的功能。Lucene适用于中小型项目 ,ES适用于中大型项目(它底层是基于lucene实现的)

2.2.Lucene索引原理

任何技术都有一些核心,Lucene也有核心,而它的核心分为:索引创建,索引搜索。接下来我们就一一的来看。

1.索引的创建

首先构造三个不同的句子,有长有短:

在①处分别为3个句子加上编号,然后进行分词,把单词分解出来与编号对应放在②处;对于搜索的过程中大写和小写指的都是同一个单词,在这就没有区分的必要,按规则统一变为小写放在③处;要加快搜索速度,就必须保证这些单词的排列时有一定规则,这里按照字母顺序排列后放在④处;最后再简化索引,合并相同的单词,就得到如下结果:倒排索引文档

通常在数据库中我们都是根据文档找到内容,而这里是通过词,能够快速找到包含他的文档,这就是文档倒排链表。

2.索引的搜索

就是得到用户的查询请求,搜索创建的索引,然后返回结果的过程。

搜索java world两个关键词,符合java的有1,2两个文档,符合world的有1,3两个文档,在搜索引擎中直接这样排列两个词他们之间是"或"的关系,出现其中一个都可以被找到,所以这里3个都会出来。

全文检索中是有相关性排序的,那么结果在是怎么排列的呢?hello java world中包含两个关键字排在第一,另两个都包含一个关键字,得到结果,hello lucene world排在第二,java在最长的句子中占的权重最低排在结果集的第三。从这里可以看出相关度排序还是有一定规则的。

二.ElasticSearch相关概念

1.ElasticSearch介绍

1.1. 为什么要使用ElasticSearch

虽然全文搜索领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。

1.2.什么是ElasticSearch

ES是一个分布式的全文搜索引擎,为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案,ES的索引库管理支持依然是基于Apache Lucene(TM)的开源搜索引擎。

ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

案例:添加索引

PUT /pethome/pet/1
{
  "id":1,
  "name":"金毛"
}

获取

GET /pethome/pet/1

总的来说ElasticSearch简化了全文检索lucene的使用,同时增加了分布式的特性,使得构建大规模分布式全文检索变得非常容易。

1.3.ES的特点
  • 分布式的实时文件存储

  • 分布式全文搜索引擎,每个字段都被索引并可被搜索

  • 能在分布式项目/集群中使用

  • 本身支持集群扩展,可以扩展到上百台服务器

  • 处理PB级结构化或非结构化数据

  • 简单的 RESTful API通信方式

  • 支持各种语言的客户端

  • 基于Lucene封装,使操作简单

1.4.ES和lucene的区别
  • Lucene只支持Java,ES支持多种语言

  • Lucene非分布式,ES支持分布式

  • Lucene非分布式的,索引目录只能在项目本地 , ES的索引库可以跨多个服务分片存储

  • Lucene使用非常复杂 ,ES屏蔽了Lucene的使用细节,操作更方便

  • 单体/小项目使用Lucene ,大项目、分布式项目使用ES

3.其他全文搜索引擎

3.1.Solr(重量级对手)

Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持。

Solr和ES比较:

Solr 利用 Zookeeper(注册中心) 进行分布式管理,支持更多格式的数据(HTML/PDF/CSV),官方提供的功能在传统的搜索应用中表现好于 ES,但实时搜索效率低。

ES自身带有分布式协调管理功能,但仅支持json文件格式,本身更注重于核心功能,高级功能多有第三方插件提供,在处理实时搜索应用时效率明显高于 ES。

3.2.Katta

基于 Lucene 的,支持分布式,可扩展,具有容错功能,准实时的搜索方案。

优点:开箱即用,可以与 Hadoop (大数据)配合实现分布式。具备扩展和容错机制。

缺点:只是搜索方案,建索引部分还是需要自己实现。在搜索功能上,只实现了最基本的需求。成功案例较少,项目的成熟度稍微差一些。

3.3.HadoopContrib

大数据相关的东西 (大数据工程师)

Map/Reduce 模式(云计算)的,分布式建索引方案,可以跟 Katta 配合使用。

优点:分布式建索引,具备可扩展性。

缺点:只是建索引方案,不包括搜索实现。工作在批处理模式,对实时搜索的支持不佳。

三.ES下载和安装

ES的安装比较简单,只需要官方下载ES的运行包,然后启动ES服务即可。ES的使用主要是通过能够发起HTTP请求的终端来接入,比如Poster插件、CURL、kibana5等。

1.ElasticSearch安装

ES服务只依赖于JDK,推荐使用JDK1.8+。本课程以在window环境下,ES 6.8.6版本为例,下载对应的ZIP文件

1.1.下载ElasticSearch

下载地址:Download Elasticsearch | Elastic

本课程以在window环境下,ES 6.8.6版本为例,下载对应的ZIP文件

1.2.安装与启动

解压即可,双击安装目录 bin/elasticsearch.bat即可启动

1.3.ElasticSearch测试

使用浏览器访问:http://localhost:9200

看到上图信息,恭喜你,你的ES集群已经启动并且正常运行.

1.4.ES内存配置

如果ES启动占用的内存比较大可以通过修改 jvm.options 文件来修改内存

2.Kibana5安装(可视化工具)

2.1.下载Kibana5

下载地址:Download Kibana Free | Get Started Now | Elastic

2.2.安装与启动

解压即可安装 , 执行bin\kibana.bat 即可启动Kibana

2.3.Kinbana连接ES配置

解压并编辑config/kibana.yml,设置elasticsearch.url的值为已启动的ES

默认情况下,Kibana会链接本地的默认ES http://localhost:9200 ,如果需要修改链接的ES服务器,通过修改安装目录下 config/kibana.yml,将配置项 #elasticsearch.url: "http://localhost:9200" 取消注释即可修改连接的ES服务器地址。

2.4.测试Kibana

浏览器访问 http://localhost:5601 Kibana默认地址

Kibana组件详细说明:https://www.cnblogs.com/hunttown/p/6768864.html

Discover:可视化查询分析器
​
Visualize:统计分析图表
​
Dashboard:自定义主面板(添加图表)
​
Timelion:Timelion是一个kibana时间序列展示组件(暂时不用)
​
Dev Tools :Console(同CURL/POSTER,操作ES代码工具,代码提示,很方便)
​
Management:管理索引库(index)、已保存的搜索和可视化结果(save objects)、设置 kibana 服务器属性。

修改为中文:找到config目录下的kibana.yml,然后添加以下这行代码即可。

i18n.locale: "zh-CN"

四.ElasticSearch基础

1.几个基本概念

1.1.Near Realtime(NRT)

近实时,含有两层两个意思,从写入数据到数据可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级

1.2Index(索引-数据库)
我们为什么使用ES?因为想把数据存进去,然后再查询出来。

我们在使用Mysql或者Oracle的时候,为了区分数据,我们会建立不同的数据库,库下面还有表的。

其实ES功能就像一个关系型数据库,在这个数据库我们可以往里面添加数据,查询数据。

ES中的索引非传统索引的含义,ES中的索引是存放数据的地方,是ES中的一个概念词汇

index类似于我们Mysql里面的一个数据库 create database user; 好比就是一个索引库

1.3 Type(类型-表)
ES6以后一个index只能有一个type,为了提高查询效率。意思就是, 一个库只能有一张表

1.4 Document(文档-行)
文档就是最终的数据了,可以认为一个文档就是一条记录。

是ES里面最小的数据单元,就好比表里面的一条数据

1.5 Field(字段-列)
好比关系型数据库中列的概念,一个document有一个或者多个field组成。

1.6 mapping(映射-约束)
数据如何存放到索引对象上,需要有一个映射配置,包括:数据类型、是否存储、是否分词等。

ElastciSearch全文搜索Mysql关系型数据库
索引库(index)数据库(database)
文档类型(Type)数据表(Table)
文档(Document)一行数据(Row)
字段(field)一个列(column)
文档ID主键ID
查询(Query DSL)查询(SQL)
GET http://..SELECT * FROM ...
PUT http://UPDATE table set...

2.索引库CRUD

索引库的crud:

创建索引库:

PUT /索引库名

查询索引库:

GET /索引库名

删除索引库:

DELETE /索引库名

添加字段映射:

PUT /索引库名/_mapping

{
  "mapping":{

"properties":{

   "字段":值
}

  }

}

说明:

1.类似于mysql的表, 在7以后, 就没有类型的概念了, 所有的数据都直接存在库中, 根据id进行区分

2.添加库中可以定义mapping映射用来约束库

--> 定义字段的名字和类型, 类似于表, 是否创建索引(默认true), 该字段是否需要分词, 分词器是什么

案例:

小提示: 在一个字段里拥有多个字段的技巧

3.文档的CRUD[重点]

3.1.添加文档

我们以员工对象为例,我们首先要做的是存储员工数据,每个文档代表一个员工。在ES中存储数据的行为就叫做索引(indexing),文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以简单的对比传统数据库和ES的对应关系:

ESMysql
_index(索引库)数据库
_type(文档类型)
_document(文档对象)一行数据
_id(文档ID)主键ID
field(字段)

ES集群可以包含多个索引(indices)(数据库),每一个索引库中可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。

文档的crud: --> 类似于mysql的一条数据

创建(插入)文档:

post /索引库/_doc/id --> 不设置id则es自动生成

{

"字段":值

"字段":{

"properties":{

"字段":值

}

}

}

查询文档:

get /索引库/_doc/id

删除文档:

delete /索引库/_doc/id

修改文档:

方式1: (全量修改) (先删除, 再添加) (没有则直接添加)

put /索引库/_doc/id

{
   数据内容;

}

方式2: (局部修改)

post /索引库/_update/id

{

需要修改的内容;

}

4.文档简单查询()[]

一. 查询: 都是在query内部

查询所有: match_all

全文检索查询: 利用分词器对用户输入的内容分词, 然后去倒排索引库中查找

match

multi_match

精确查询: 不需要分词, 直接查找( keyword, 数值, 日期 )

range

term

地理查询: 根据经纬度进行查询

geo_distance

geo_bounding_box: 一个矩阵范围内

复合查询: 多个查询条件, 组合成新的查询

bool

function_score

示例:

get /索引库/_search

{

"query": { --> 表示以下为查询结构

"查询类型" : {

"查询条件(字段)": "条件值(字段值)"

}

}

}

案例1: 查询所有

get /索引库/_search

{

  "query": {

    "match_all": {

    }

  }

}

案例2: 匹配单个查询

get /索引库/_search

{

  "query":{ --> 表示以下为查询结构

    "match":{ --> 只能匹配一个字段

  "address":"银河系"

}

  }

}

案例3: 匹配多个查询 (查询的字段越多, 效率就越低) --> 建议: 使用copy_to 将多个字段 拷贝到 一个字段中

get /索引库/_search

{

  "query": {

    "multi_match": {

      "query": "银河三", --> 查询的字段

      "fields": ["address","name"] --> 任意一个字段内有query分词后的值, 那么就匹配成功

    }

  }

}

案例4: 精确查询匹配 (必须完全等于字段值)

get /索引库/_search

{

  "query": {

    "term": { --> 只能用于 不分词的字符串, 数值, 日期, boolean等

      "id": {

        "value": "1"

      }

    }

  }

}

案例4: 范围查询匹配

get /索引库/_search

{

  "query": {

    "range": { --> 数值, 日期 …

      "age": {

        "gte": 10, --> gte 大于等于, gt 大于, lte 小于等于, lt 小于, eq 等于

        "lte": 25

      }

    }

  }

}

地理查询:

1.范围矩阵查询:

2.附近查询:

五.复杂查询&结果集处理

二.复合查询:

1.Function Score 修改分数

调整分数:

分数指: 权重比例, 所搜索的字段在某个值中, 权重越大, 越靠前

当需要将某个字段进行手动提前: 使用function_score---functions--boost_mode

蓝色: 本身原来的分数

黄色: 过滤

绿色: 额外给他的分

紫色: 本身的分数 与 额外的分数 进行运算 ( 有替换, 相加, 相乘, 取大, 取小, 平均, …….. )

2.Boolean 布尔查询

must: 必须匹配每一个子查询 --> 与

should: 选择性匹配子查询 --> 或

must_not: 必须不匹配, 不参与算分 --> 非

filter: 必须匹配, 不参与算分

三.搜索结果处理:

1.排序: 默认根据相关度算分排序

可以根据某个数值进行排序: 数值, 日期, 地理坐标

数值和地理坐标(lat纬度, lon经度):

2.分页:

缺点: 获取前1000, 截取990-1000的数据

但在实际生产环境下是集群模式, 数据会分为多个分片

分片: 如图

如果页数越深, 也就是结果集(from + size)越大, 对内存和cpu的消耗就越高, 这样性能会大大降低

因此, ES设定结果集查询的上限是 一万 , 多一个就会查询报错

针对深度分页, es解决方案两个:

search after: 分页时, 需要排序, 原理:从上一页排序值开始, 查询下一页的数据, 官方推荐

scroll: 原理: 将排序数据形成快照, 保存在内存, 官方已经不推荐使用了

3.高亮:

原理:

就是将搜索结果中的关键字用标签标记出来, 并添加css样式

注意:

查询的类型不可以是match_all或同类型的全部查询, 只能是带有关键字的查询

ES搜索的字段名必须与高亮字段名一致(使用copy_to将多个字段放到一个字段A中时, 该字段A不可以使用高亮)

如果非要使用集合字段可以在高亮字段内部添加: require_field_match = false  表示不匹配字段

其他DSL查询请参考官方文档:  Elasticsearch Guide [8.11] | Elastic

六.分词器安装和使用

1.基本概念

1.1.什么是分词

在全文检索理论中,文档的查询是通过关键字查询文档索引来进行匹配,因此将文本拆分为有意义的单词,对于搜索结果的准确性至关重要,因此,在建立索引的过程中和分析搜索语句的过程中都需要对文本串分词。ES的倒排索引是分词的结果。

1.2.理解分词的作用

分词器的作用至关重要,数据的查询结果是否精准跟分词器有很大的关系

为了方便理解,我们用一个模拟图跟踪一下ES创建倒排索引的过程,如有原始数据:

IDusernameintro
1zsmy name is zs
2lsmy name is ls

如果对intro进行倒排索引,ES会根据分词器进行分词 , 语义转换,排序, 分组等操作最终倒排索引如下:

词元ID倒排
is1 -> 2
ls2
my1 -> 2
name1 -> 2
zs1

当ES进行关键字查询的时候,如需要查询“my” ,那么ES可以根据二分查找更快的定位到 my | 1 -> 2 , 根据ID值1 ,2直接取出结果。

2.IK分词器

2.1.为什么用IK分词器

ES默认对英文文本的分词器支持较好,但和lucene一样,如果需要对中文进行全文检索,那么需要使用中文分词器,同lucene一样,在使用中文全文检索前,需要集成IK分词器 - 大家都在用IK

2.2.安装IK分词器
1.下载ES的IK分词器

插件源码地址:GitHub - medcl/elasticsearch-analysis-ik: The IK Analysis plugin integrates Lucene IK analyzer into elasticsearch, support customized dictionary.

2.解压elasticsearch-analysis-ik-5.2.2.zip文件

并将解压后的内容放置于ES根目录/plugins/ik

3.IK分词器配置

在ik/config 目录可以对分词器进行配置,如停词 , 自定义字典等。

4.IK分词测试
POST _analyze
{
  "analyzer":"ik_smart",
  "text":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
}

提示:IK分词器指定:ik_smart ; ik_max_word , ik_max_word 相比 ik_smart 来说会将文本做最细粒度的拆分。

七.文档类型映射

简单来说就是涉设计表的结构, 每一个字段的类型啊分词器啊等等

1.基本概念

1.1.什么是文档映射

ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型。就如果Mysql创建表时候指定的每个column列的类型。 为了方便字段的检索,我们会指定存储在ES中的字段是否进行分词,但是有些字段类型可以分词,有些字段类型不可以分词,所以对于字段的类型需要我们自己去指定。

需要注意的是,我们在Mysql建表过程是:

Mysql创建数据库 -> 创建表(指定字段类型) -> crud数据 而在ES中也是一样,

ES创建索引库 -> 文档类型映射 -> crud文档

1.2.默认的字段类型

查看索引类型的映射配置:GET {indexName}/_mapping/{typeName}

  • 基本字段类型

字符串text(分词) ;keyword(不分词) ;StringField(不分词文本);TextFiled(要分词文本)
数字longintegershortdoublefloat
日期date
逻辑boolean
  • 复杂字段类型

对象类型object
数组类型array
地理位置geo_point,geo_shape
  • 默认映射

ES在没有配置Mapping的情况下新增文档,ES会尝试对字段类型进行猜测,并动态生成字段和类型的映射关系。

内容默认映射类型
JSON typeField type
Boolean: true or false"boolean"
Whole number: 123"long"
Floating point: 123.45"double"
String, valid date:"2014-09-15""date"
String: "foo bar""text"
1.3.映射规则

字段映射的常用属性配置列表 - 即给某个字段执行类的时候可以指定以下属性

==type==类型:基本数据类型,integer,long,date,boolean,keyword,text...
enable是否启用:默认为true。 false:不能索引、不能搜索过滤,仅在_source中存储
boost权重提升倍数:用于查询时加权计算最终的得分。
format格式:一般用于指定日期格式,如 yyyy-MM-dd HH:mm:ss.SSS
ignore_above长度限制:长度大于该值的字符串将不会被索引和存储。
ignore_malformed转换错误忽略:true代表当格式转换错误时,忽略该值,被忽略后不会被存储和索引。
include_in_all是否将该字段值组合到_all中。
null_value默认控制替换值。如空字符串替换为”NULL”,空数字替换为-1
store是否存储:默认为false。true意义不大,因为_source中已有数据
==index==索引模式:analyzed (索引并分词,text默认模式), not_analyzed (索引不分词,keyword默认模式),no(不索引)
==analyzer==索引分词器:索引创建时使用的分词器,如ik_smart,ik_max_word,standard
==search_analyzer==搜索分词器:搜索该字段的值时,传入的查询内容的分词器。
==fields==多字段索引:当对该字段需要使用多种索引模式时使用。如:城市搜索 New York"city":"city":{
"type": "text",   
"analyzer": "ik_smart",   
"fields": {      
	"raw": {         
		"type":  "keyword"       
	}   
}

} 解释:相当于给 city取了一个别名 city.raw,city的类型为text , city.raw的类型keyword 搜索 city分词 ; 搜索city.raw 不分词那么以后搜索过滤和排序就可以使用city.raw字段名 |

2.添加映射

注意:如果索引库已经有数据了,就不能再添加映射了

2.1.创建新的索引库
put aigou
2.2.单类型创建映射
put aigou/goods/_mapping
{
	"goods": {
        "properties": {
            "id": {
                "type": "long"
            },
            "name": {
                "type": "text",
                "analyzer": "ik_smart",
                "search_analyzer": "ik_smart"
            }
        }
    }
}

解释:给aigou索引库中的是goods类型创建映射 ,id指定为long类型 , name指定为text类型(要分词),analyzer分词使用ik,查询分词器也使用ik

2.3.多类型创建映射
PUT aigou
{
  "mappings": {
    "user": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "info": {
          "type": "text",
          "analyzer": "ik_smart",
          "search_analyzer": "ik_smart"
        }
      }
    },
    "dept": {
      "properties": {
        "id": {
          "type": "integer"
        },
        ....更多字段映射配置
      }
    }
  }
}

解释:同时给user和dept创建文档映射

2.4.数组/对象映射

基本类型字段映射非常简单,直接配置对应的类型即可,但是数组和对象如何指定类型呢?

1.对象映射
{
  "id" : 1,
  "girl" : {
      "name" : "王小花",
      "age"  : 22
     
  }
}

文档映射

{ 
  "properties": {
       "id": {"type": "long"},
       "girl": {
           "properties":{
           		"name": {"type": "keyword"},
           		"age": {"type": "integer"}
           }
        }
  }
}
2.数组映射
{
	"id" : 1,
	"hobby" : ["王小花","林志玲"]
}

文档映射

{ 
		"properties": {
            "id": {"type": "long"},
            "hobby": {"type": "keyword"}
     }
}

解释:数组的映射只需要映射一个元素即可,因为数组中的元素类型是一样的。

3.对象数组
{
	"id" : 1,
	"girl":[{"name":"林志玲","age":32},{"name":"赵丽颖","age":22}]
}

文档映射

"properties": {
        "id": {
            "type": "long"
        },
        "girl": {
            "properties": {
              "age": { "type": "long" },
              "name": { "type": "text" }
            }
        }
}
2.5.全局映射(了解)

索引库中多个类型(表)的字段是有相同的映射,如所有的ID都可以指定为integer类型,基于这种思想,我们可以做全局映射,让所有的文档都使用全局文档映射。全局映射可以通过动态模板和默认设置两种方式实现。

  • 默认方式:default

索引下所有的类型映射配置会继承default的配置,如:

PUT {indexName}
{
 "mappings": {
    "_default_": { 
       "_all": {
        	"enabled": false
       }
  },
  "user": {}, 
  "dept": { 
     "_all": {
      	"enabled": true
     }
  }
 }

关闭默认的 all ,dept自定义开启 _all

  • 动态模板

在实际应用场景中,一个对象的属性中,需要全文检索的字段较少,大部分字符串不需要分词,因此,需要利用全局模板覆盖自带的默认模板

PUT _template/global_template  //创建名为global_template的模板
{
  "template":   "*",  //匹配所有索引库
  "settings": { "number_of_shards": 1 }, //匹配到的索引库只创建1个主分片
  "mappings": {
    "_default_": {
      "_all": { 
        "enabled": false //关闭所有类型的_all字段
      },
      "dynamic_templates": [
        {
          "string_as_text": { 
            "match_mapping_type": "string",//匹配类型string    username="xxx xxx"
            "match":   "*_text", //匹配字段名字以_text结尾
            "mapping": {
              "type": "text",//将类型为string的字段映射为text类型
              "analyzer": "ik_max_word",
              "search_analyzer": "ik_max_word",
              "fields": {
                "raw": {
                  "type":  "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        {
          "string_as_keyword": { 
            "match_mapping_type": "string",//匹配类型string
            "mapping": {
              "type": "keyword"//将类型为string的字段映射为keyword类型
             }
          }
        }
      ]
    }
  }}

PS : 映射方式优先级 (低 -> 高):默认 -> 全局 -> 自定义

八.JavaApi操作ES

1.集成ES

官方文档API:Java Transport Client (deprecated) | Elastic

1.依赖:

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>

        </dependency>

2.利用RestHighLevelClient对象来发送请求操作索引库(需要注入)--restHighLevelClient

也可以选择手动配置:

RestHighLevelClient选择手动配置: 配置类 静态工厂

构建 RestClientBuilder 对象并指定 IP 端口 协议:

RestClientBuilder builder = RestClient.builder(new HttpHost("127.0.0.1", 9200, "http"),可以有多个);

创建 RestHighLevelClient, 并返回:

RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);

3.步骤:

a: 创建Request请求

b: 设置请求体参数内容及类型: DSL语句(put, post)

c: 发送请求

d: 得到结果并解析(get)

4.代码实现:

1.创建/删除/获取 索引库:

a:创建Request请求

new CreateIndexRequest("索引库名"); --> 创建索引库request

new DeleteIndexRequest("索引库名"); --> 删除索引库request

new GetIndexRequest("索引库名"); --> 获取索引库request

b: 设置请求体参数内容及类型: DSL语句

request.source("请求体内容JSON格式", "Xcontent.JSON数据类型") --> 创建索引库 DSL

c: 发送请求

restHighLevelClient.indices().create/delete/exists/…(request请求对象, RequestOptions.DEFAULT请求选项)

说明: indices是对索引库的操作

2.添加/删除/修改/查询 文档:

a: 创建Request请求

new IndexRequest("索引库名").id("id值"); --> 创建添加文档的Request

new GetRequest("索引库名").id("id值"); --> 创建查询文档的Request

new UpdateRequest("索引库名").id("id值"); --> 创建修改文档的Request

new DeleteRequest("索引库名").id("id值"); --> 创建删除文档的Request

b: 设置请求体参数内容及类型: DSL语句(put, post)

indexRequest.source(JSON.toJSONString(对象), XContentType.JSON内容类型); --> 添加

updateRequest.doc(JSON.toJSONString(user), XContentType.JSON); --> 更新(修改), 当手写字段值时, 中间不是冒号, 而是逗号

  "字段","", …

 c: 发送请求

restHighLevelClient.index/get/update/delete( Request请求, RequestOptions.DEFAULT请求选项);

d: 得到结果并解析(get)

get请求查询文档后得到响应结果, 需要进行解析: 结果对象.getSourceAsString(); --> 得到json字符串

还可以将json字符串转换成对象: --> JSON.parseObject(json字符串, 类别.class);

 

 

3.查询文档

a: 创建Request请求

new SearchRequest();

b: 设置请求体参数内容及类型: DSL语句(put, post)

查询模板: searchRequest.source().query(QueryBuilders.matchQuery/termQuery/…("字段", "字段值"))

复合查询模板: searchRequest.source().query(QueryBuilders.boolQuery().must/filter/…(QueryBuilders.termQuery("字段", "字段值")));

分页模板: searchRequest.source().from(xxx).size(xxx);

排序模板: searchRequest.source().sort(SortBuilders.[xxx/……].order(SortOrder.ASC)); --> SortOrder 来选择怎样排序, 其他不变

高亮模板:searchRequest.source().highlighter(new Highlighter().field("高亮的字段").requireFieldMatch(false));

查询案例:

searchRequest.source().query(QueryBuilders.matchAllQuery());

searchRequest.source().query(QueryBuilders.matchQuery/termQuery("字段", "字段值"));

searchRequest.source().query(QueryBuilders.rangeQuery("字段").gte());

searchRequest.source().query(QueryBuilders.boolQuery().must/filter/…(QueryBuilders.term("字段", "字段值")));

………

总的来说: QueryBuilders就是在构建条件, 按照DSL格式来逐层递进

, SortBuilders同理

c: 发送请求

restHighLevelClient.search( Request请求, RequestOptions.DEFAULT请求选项 )

d: 得到结果并解析(get)

解析结果集

searchResponse.getHits(); --> 拿到内容, 解析结果hits

hits.getTotalHits().value; --> 拿到结果的总条数

hits.getHits(); --> 查询的结果数组

遍历数组

得到每一个source 转化成字符串 getSourceAsString();

并打印

 

高亮解析:

5.分类:

添加文档操作: IndexRequest --> 涉及步骤[ a, b, c ]

查询文档操作: GetRequest --> 涉及步骤[ a, c, d ]

修改文档操作: UpdateRequest --> 涉及步骤[ a, b, c ]

删除文档操作: DeleteRequest --> 涉及步骤[ a, c ]

6.批量新增(导入)功能:

思路:

查询所有数据

类型转换: 对象类型 转为 文档类型

利用Bulk批处理

实现:

a:

创建批量请求: --> new BulkRequest();

b:

添加要批量的请求: --> bulkRequest.add( new IndexRequest("索引库").id(…).source(…) )

bulkRequest.add( new IndexRequest("索引库").id(…).source(…) )

………

c:

发送请求: --> restHighLevelClient.bulk( bulkRequest请求 , RequestOptions.DEFAULT请求选项)

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值