当前位置:首页 > 资讯 > 正文

原生语言操作和spring data中RestHighLevelClient操作Elasticsearch,索引,文档的基本操作,es的高级查询.查询结果处理. 数据聚合.相关性系数打分

原生语言操作和spring data中RestHighLevelClient操作Elasticsearch,索引,文档的基本操作,es的高级查询.查询结果处理. 数据聚合.相关性系数打分

​ Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。

​ RestHighLevelClient 底层封装的是一个http连接池,当需要执行 update、index、delete操作时,直接从连接池中取出一个连接,然后发送http请求到ElasticSearch服务端,服务端基于Netty接收请求。

​ 新版本的elasticsearch java client 都推荐用RestHighLevelClient去连接ES集群,放弃掉之前的transport client的方式。

注:spring boot工程

 
 
 
 
 
 
 
 
 
 

如mapper类,service类就自己去创建。

3.1.1 mapping映射属性

​ mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:
    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值:long、integer、short、byte、double、float、
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建倒排索引,默认为true
  • analyzer:使用哪种分词器
  • properties:该字段的子字段

3.1.2 es语法

  • 请求方式:PUT

  • 请求路径:/索引库名,可以自定义

  • 请求参数:mapping映射

 
  • location:地理坐标,里面包含精度、纬度
  • all:一个组合字段,其目的是将多字段的值 利用copy_to合并,提供给用户搜索

测试结果

3.1.3 java语法

 
 

3.2.1 es语法

  • 请求方式:GET

  • 请求路径:/索引库名

  • 请求参数:无

     

    测试结果

3.2.2 java语法

 

测试结果

索引库一旦创建,无法修改mapping

虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。

3.3.1 es语法

  • 请求方式:PUT

  • 请求路径:/索引库名/_mapping

  • 请求参数:mapping映射

     

    测试结果

3.4.1 es语法

  • 请求方式:DELETE

  • 请求路径:/索引库名

  • 请求参数:无

      

3.4.2 Java语法

 
 
 

4.1.1 es语法

  • 请求方式:POST

  • 请求路径:/索引库名/_doc/文档id

  • 请求参数:Json

     

    测试结果

4.1.2 Java语法

 

测试结果

4.1.3 Elasticsearch数据刷新策略

 
 

4.2.1 es语法

  • 请求方式:GET

  • 请求路径:/索引库名/_doc/文档id

  • 请求参数:无

     

    测试结果

4.2.2 Java语法

 

测试结果

4.3.1 全量修改

全量修改是覆盖原来的文档,其本质是:

  • 根据指定的id删除文档
  • 新增一个相同id的文档

注意:如果根据id删除时,id不存在,第二步的新增也会执行,也就从修改变成了新增操作了。

4.3.1.1 es语法
  • 请求方式:PUT

  • 请求路径:/{索引库名}/_doc/文档id

  • 请求参数:Json

     

    测试结果

查询文档,结果已经覆盖

4.3.1.2 Java语法
 

测试结果

4.3.2 增量修改

增量修改是只修改指定id匹配的文档中的部分字段。

4.3.2.1 es语法
  • 请求方式:POST

  • 请求路径:/{索引库名}/_update/文档id

  • 请求参数:json

     

    测试结果

查询文档

4.3.2.2 Java语法
 
 

4.4.1 es语法

  • 请求方式:DELETE

  • 请求路径:/{索引库名}/_doc/id值

  • 请求参数:无

     

    测试结果

4.4.2 Java语法

 

测试结果

 
 

Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括:

  • 查询所有:查询出所有数据

    • match_all
  • 全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配

    • match_query
    • multi_match_query
  • 精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段

    • ids
    • range
    • term
  • 地理(geo)查询:根据经纬度查询

    • geo_distance
    • geo_bounding_box
  • 复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件

    • bool
    • function_score

查询的语法基本一致:

  • 请求方式:GET

  • 请求路径:/{索引库名}/_search

  • 请求参数:json

     

5.1.1 es语法

 

测试结果

5.1.2 java语法

 

测试结果

全文检索查询的基本流程如下:

  • 对用户搜索的内容做分词,得到词条
  • 根据词条去倒排索引库中匹配,得到文档id
  • 根据文档id找到文档,返回给用户

比较常用的场景包括:

  • 商城的输入框搜索

  • 百度输入框搜索

  • match查询:单字段查询

  • multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件,参与查询字段越多,查询性能越差

5.2.1 es语法

5.2.1.1 match查询
 

测试结果

5.2.1.2 multi_match查询
 

测试结果

5.2.2 Java语法

5.2.2.1match查询
 

测试结果

5.2.2.2multi_match查询
 

测试结果

5.2.3 注意

可以看到,两种查询结果是一样的,是因为mapping映射中我们将brand、name、business值都利用copy_to复制到了all字段中。因此你根据三个字段搜索,和根据all字段搜索效果当然一样了。

但是,搜索字段越多,对查询性能影响越大,因此建议采用copy_to然后单字段查询的方式

精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词

  • term查询:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段
  • range查询:根据数值范围查询,可以是数值、日期的范围

5.3.1 es语法

5.3.1.1 term查询

term单值

 

测试结果

terms

 

测试结果

term多字段

5.3.1.2 range查询
 

测试结果

5.3.2 Java语法

5.3.2.1 term查询

term单值

 

terms多值

 

term多字段

 
5.3.2.2 range查询
 
 
  • 矩形范围查询,也就是geo_bounding_box查询,查询坐标落在某个矩形范围的所有文档:

    查询时,需要指定矩形的左上右下两个点的坐标,然后画出一个矩形,落在该矩形内的都是符合条件的点。

  • 附近查询,也叫做距离查询(geo_distance):查询到指定中心点小于某个距离值的所有文档

    换句话来说,在地图上找一个点作为圆心,以指定距离为半径,画一个圆,落在圆内的坐标都算符合条件:

  • 多边形查询(geo_polygon),以多个点,确定多边形,获取多边形内的全部数据,与矩形相似,只不过是多个点

5.4.1 es语法

5.4.1.1 矩形范围查询
 

测试结果

5.4.1.2 附近查询
 

测试结果

5.4.1.3 多边形查询
 

测试结果

5.4.2 Java语法

5.4.2.1 矩形范围查询
 
5.4.2.2 附近查询
 
5.4.2.3 多边形查询
 
 

复合(compound)查询:复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑。常见的有两种:

  • fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名
  • bool query:布尔查询,利用逻辑关系组合多个其它的查询,实现复杂搜索

5.5.1 相关性算分

当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列。

  • TF-IDF算法

    TF-IDF算法有一各缺陷,就是词条频率越高,文档得分也会越高,单个词条对文档影响较大

  • BM25算法,elasticsearch5.1版本后采用的算法

    BM25则会让单个词条的算分有一个上限,曲线更加平滑

5.5.2 算分函数查询

​ 根据相关度打分是比较合理的需求,但合理的不一定是产品经理需要的。

​ 以百度为例,你搜索的结果中,并不是相关度越高排名越靠前,而是谁掏的钱多排名就越靠前.

​ 要想认为控制相关性算分,就需要利用elasticsearch中的function score 查询了。

5.5.2.1 es语法
 

function score 查询中包含四部分内容:

  • 原始查询条件:query部分,基于这个条件搜索文档,并且基于BM25算法给文档打分,原始算分(query score)
  • 过滤条件:filter部分,符合该条件的文档才会重新算分
  • 算分函数:符合filter条件的文档要根据这个函数做运算,得到的函数算分(function score),有四种函数
    • weight:函数结果是常量
    • field_value_factor:以文档中的某个字段值作为函数结果
    • random_score:以随机数作为函数结果
    • script_score:自定义算分函数算法
  • 运算模式:算分函数的结果、原始查询的相关性算分,两者之间的运算方式,包括:
    • multiply:相乘
    • replace:用function score替换query score
    • 其它,例如:sum、avg、max、min

function score的运行流程如下:

  • 1)根据原始条件查询搜索文档,并且计算相关性算分,称为原始算分(query score)
  • 2)根据过滤条件,过滤文档
  • 3)符合过滤条件的文档,基于算分函数运算,得到函数算分(function score)
  • 4)将原始算分(query score)和函数算分(function score)基于运算模式做运算,得到最终结果,作为相关性算分。

因此,其中的关键点是:

  • 过滤条件:决定哪些文档的算分被修改

  • 算分函数:决定函数算分的算法

  • 运算模式:决定最终算分结果

测试结果

5.5.2.2 java语法
 

5.5.3 布尔查询

布尔查询是一个或多个查询子句的组合,每一个子句就是一个子查询。子查询的组合方式有:

  • must:必须匹配每个子查询,类似“与”
  • should:选择性匹配子查询,类似“或”
  • must_not:必须不匹配,不参与算分,类似“非”
  • filter:必须匹配,不参与算分

需要注意的是,搜索时,参与打分的字段越多,查询的性能也越差。因此这种多条件查询时,建议这样做:

  • 搜索框的关键字搜索,是全文检索查询,使用must查询,参与算分
  • 其它过滤条件,采用filter查询。不参与算分
5.5.3.1 es语法
 

测试结果

5.5.3.2 java语法
 
 
 

​ elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

6.1.1 普通字段排序

​ keyword、数值、日期类型排序的语法基本一致。

6.1.1.1 es语法
 

测试结果

6.1.1.2 java语法
 

6.1.2 地理坐标排序

6.1.2.1 es语法
 
  • 指定一个坐标,作为目标点
  • 计算每一个文档中,指定字段(必须是geo_point类型)的坐标 到目标点的距离是多少
  • 根据距离排序

测试结果

6.1.2.2 java语法
 
 

elasticsearch 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。elasticsearch中通过修改from、size参数来控制要返回的分页结果:

  • from:从第几个文档开始
  • size:总共查询几个文档

6.2.1 es语法

 

测试结果

6.2.2 java语法

 

6.2.3深度分页问题

高亮显示的实现分为两步:

  1. 给文档中的所有关键字都添加一个标签,例如标签
  2. 页面给标签编写CSS样式

6.3.1 es语法

 

注意:

  • 高亮是对关键字高亮,因此搜索条件必须带有关键字,而不能是范围这样的查询。
  • 默认情况下,高亮的字段,必须与搜索指定的字段一致,否则无法高亮
  • 如果要对非搜索字段高亮,则需要添加一个属性:required_field_match=false

测试结果

6.3.2 Java语法

 

测试结果

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

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

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

聚合常见的有三类:

  • **桶(Bucket)**聚合:用来对文档做分组

    • TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
    • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
  • **度量(Metric)**聚合:用以计算一些值,比如:最大值、最小值、平均值等

    • Avg:求平均值
    • Max:求最大值
    • Min:求最小值
    • Stats:同时求max、min、avg、sum等
  • **管道(pipeline)**聚合:其它聚合的结果为基础做聚合

**注意:**参加聚合的字段必须是keyword、日期、数值、布尔类型

7.2.1 TermAggregation

7.2.1.1 es语法
 
7.2.1.2 java语法
 

继承关系图

7.2.2 Date Histogram

参数

  1. field:要聚合的日期字段名称。
  2. interval:指定聚合的时间间隔。可以是秒、分、小时、天、周、月或年。
  3. format:指定日期格式,用于解析日期字段。默认为“epoch_millis”格式。
  4. time_zone:指定时区。默认为UTC。
  5. min_doc_count:指定每个时间间隔内最少需要包含的文档数。默认为0。
  6. order:指定排序方式,可以是升序(asc)或降序(desc)。
  7. extended_bounds:指定扩展范围,允许返回超出时间间隔的结果。可以指定min和max值。
  8. missing:指定当日期字段缺失时的聚合方式。可以是“_count”(返回缺失值数量)或“_key”(返回指定的缺失值)。
 
 

7.3.1 Avg/Max/Min

7.3.1.1 es语法
 

测试结果

7.3.2 Stats:同时求max、min、avg、sum等

7.3.2.1 es语法
 

测试结果

7.3.2.2 Java语法