文档章节

全文搜索引擎 ElasticSearch

麦拂沙
 麦拂沙
发布于 2017/05/25 01:57
字数 2990
阅读 131
收藏 0

ElasticSearch是一个基于Lucene的分布式多用户全文搜索引擎,使用Json索引,提供RESTful API,有着极高的实时搜索性能。

基础知识

ES主要功能

  • 全文搜索引擎(倒排索引:根据词找到 位置&频次)
  • 数据分析系统(尤其是时间序列数据的聚合分析)
  • 分布式实时存储系统

优点

  • 高效的分词搜索
  • 强大的聚合运算

ES特性

  • 集群由主节点(负责管理集群所有变更)和普通节点组成
  • 索引被切割为分片调配到集群节点上(分片上并存着原始文档),主分片数在索引创建时即已确定
  • 副本分片用于实现故障切换,负载均衡(分片的备份套数随时可变)

索引结构

  • 分片、副本等配置
  • Type Mapping配置,包含:
    • 元数据配置
    • 字段域的类型、索引及搜索方式

健康状态

  • 绿色:所有主副分片均正常
  • 黄色:副本分片存在不正常
  • 红色:主分片有存在不正常

Mysql概念对比

Mysql : ES 关系对比

  • 数据库 : 索引 index
  • 表 : 类型 type
  • 行 : 文档 document
  • 列 : 字段 field
  • Schema : 映射 mapping
  • SQL : DSL

Index VS Type

在具体存储空间选型时需要考虑一下几点:

  • Index由一系列分片组成, 每个分片即一个Lucene索引实例并存在磁盘,内存,文件句柄的开销
  • 查询结果时,ES需要合并所有相关Index下的所有分片的结果集
  • 同Index下的不同Type有资源争用问题
  • 相关性得分在Index范围内计算, 不同类型Type会相互影响判分

存储空间选型建议:
一般一种文档数据即占用一个INDEX空间,除非满足以下条件可考虑TYPE空间

  • 两种文档有明显父子关系
  • 两种文档有类似的mapping结构
  • 每个Type下的文档量级不是特别大

基于Docker安装

DockerFile:

FROM elasticsearch:2.3.5

# head插件
RUN /usr/share/elasticsearch/bin/plugin install mobz/elasticsearch-head

# IK分词安装
RUN mkdir /usr/share/elasticsearch/plugins/analysis-ik \
	&& cd /usr/share/elasticsearch/plugins/analysis-ik \
	&& wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v1.9.5/elasticsearch-analysis-ik-1.9.5.zip \
	&& unzip elasticsearch-analysis-ik-1.9.5.zip \
	&& rm -fr elasticsearch-analysis-ik-1.9.5.zip

镜像构建与启动:

  • API服务端口:9200
  • 集群节点通信端口:9300
docker build -t test/elasticsearch .
docker run -d -p 9200:9200 -p 9300:9300 --name=es test/elasticsearch

# 检查插件(应该会罗列head、 analysis-ik两个插件)
docker exec es bin/elasticsearch-plugin list

访问:

  • API接口:http://localhost:9200
  • head插件:http://192.168.137.4:9200/_plugin/head

中文分词

analyzer分析器由以下组成:

  • char_filter字符过滤器
  • tokenizer分词器
  • filter词条过滤器

IK分词:

  • 支持自定义本地词库
    • plugins/analysis-ik/config/custom/mydict.dic文件中追加自定义词条
    • 重启ES服务
    • 重建相关数据的索引
  • 支持热更新远程词库
    • plugins/analysis-ik/config/IKAnalyzer.cfg.xml中配置utf-8远程词库remote_ext_dict地址
    • 词库地址http头部需返回Last-Modified、ETag,任一值变动都会触发IK插件进行词库热更新
    • 常规WebServerclient请求文件的内容发生变更时 会自动更新Last-Modified、ETag两个头部信息
  • 可用分词器
    • ik_smart: 会做最粗粒度的拆分
    • ik_max_word: 会将文本做最细粒度的拆分

测试分词器

curl -XGET 'http://localhost:9200/索引/_analyze?analyzer=ik&pretty=true&text=xxx'

索引管理

  • 初始化Index curl -XPUT http://localhost:9200/索引
  • 创建Type Mapping
        curl -XPUT http://localhost:9200/索引/_mapping/类型 -d'
        {
           "properties": {
              "字段": {
                   "type": "text", #byte、integer、float、string、date、boolean、geo_point、geo_shape、nested(用于嵌套的对象数组)、object(用于对象,对象会被扁平化处理)
                   "index": "analyzed", #analyzed(全文搜索)、not_analyzed(精确值搜索)、no(不可搜索);
                   "analyzer": "ik_max_word",

                    "include_in_all": true, #该字段是否要包含在_all字段中进行搜索
                    "fields": {
                        "子字段1": {
                            "type": "string"
                        }
                    }
               }
           }
        }

        #子字段查询标识
        字段.子字段1

        # 默认索引模式
        - string类型默认`analyzed`
        - 其他简单类型默认`not_analyzed`
  • Index文档
    • 指定id curl -XPUT http://localhost:9200/索引/类型/id -d'xxx'
    • 自动id curl -XPOST http://localhost:9200/索引/类型 -d'xxx'
  • Index更新 curl -XPUT http://localhost:9200/索引/类型/id -d'xxx'
  • Index删除 curl -XDELETE http://localhost:9200/索引
  • 检索文档 curl -XGET http://localhost:9200/索引/类型/id

基本查询

curl -XGET http://localhost:9200/索引/类型/_search?查询字符串

查询字符串:

  • q匹配参数q=xxx:yyy
    • 如果q参数没有指定字段,则查询 _all 字段(所有字段值拼接成的大字符串)
    • +追加匹配条件,-追加不匹配条件
  • sort排序参数 sort=字段:desc|asc
    • sort可指定多次

复合查询

DSL请求体形式 curl -XPOST http://localhost:9200/_search -d'DSL请求体' (注意请求类型是post)

DSL请求体

  • 空查询 {}
  • DSL查询表达式 {query:查询表达式, sort:排序, from:起始数, size:每页文档数}

查询模式

  • filters过滤模式:高效 不评分查询(结果缓存)
  • queries搜索模式:低效 评分查询(结果不缓存) 一般query前先filter来缩减查询规模

查询表达式

  • 单一查询语句
    • 不指定字段 {查询方法: 值}
    • 指定了字段 {查询方法: {字段:值}}
  • bool合并查询语句
	{
	    bool:{
		    合并关系: 查询语句 或 [查询语句],
		    ...
	    }
	}

查询语句合并关系
每个子查询有自己的评分,在bool时合并评分,以下每个合并关系每个bool的直接下级中只能调用一次

  • filter 必须匹配(不评分模式的过滤)
  • must 必须匹配(评分模式的搜索)
  • must_not 必须不匹配
  • should 希望匹配(匹配其一则加分,用于修正相关性)
  • minimum_should_match 指定should方式的最小匹配次数
    bool查询若只有filter则可替换为constant_score查询,从而使评分为常量值

常见查询语句

  • match_all 匹配所有文档(默认查询方法){match_all: {}}
  • match 标准查询(字段配置决定全文或精确查询){match: {字段: 值}}
  • multi_match 多字段匹配 {multi_match: {query:值, fields:[字段1, ...]}}
  • range 区间查询 {range: {字段:{gte:最小值,lt:最大值}}}
  • term 精确值查询 {term: {字段:值}}
  • terms 多值精确查询(等于其一就行){terms: {字段:[值1,...]}}
  • exists、missing 字段有值判断 {exists: {field:字段}}
  • nested 嵌套查询 {nested: {path:上级字段, query:查询表达式}}

注意

  • term 和 terms 是 包含(contains) 操作,而非 等值(equals),即 { "term" : { "tags" : "search" } } 可以匹配字段 { "tags" : ["search", "open_source"] }
  • 参考 https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/finding_multiple_exact_values.html#%E5%8C%85%E5%90%AB_%E8%80%8C%E4%B8%8D%E6%98%AF%E7%9B%B8%E7%AD%89

查询调试

  • 校验语法:curl -XGET http://localhost:9200/索引/类型/_validate/query -d{}
  • 解释校验:curl -XGET http://localhost:9200/索引/类型/_validate/query?explain -d{}
  • 解释评分
    • 面向常规查询:curl -XGET http://localhost:9200/_search?explain&format=yaml -d{}
    • 面向指定文档:curl -XGET http://localhost:9200/索引/类型/ID/_explain -d{}

查询排序

默认相关性得分降序排列 curl -XGET http://localhost:9200/索引/类型/_search -d'{query:查询表达式, sort:排序, from:起始数, size:每页文档数}'

查询结果集排序:

  • 单字段排序
    • 排序字段单值 {字段: {order:desc|asc}}
    • 排序字段多值 {字段: {order:desc|asc, mode:归一模式}}
      • 归一模式:min、max、avg、sum、
    • index:analyzedString会被ES处理成多值字段
  • 多字段排序 [{字段1: {order:desc|asc}}, ...]

注意:

  • 尽量在index:not_analyzed字段上进行排序
  • 然而在index:analyzed字段上排序极耗内存

查询高亮

请求结构 curl -XGET http://localhost:9200/索引/类型/_search -d'{query:查询表达式, highlight:高亮表达式}'

高亮表达式:

{
    pre_tags : [<tag1>],
    post_tags : [</tag1>],
    fields : {
        _all: {
            pre_tags : [<tag1>],
            post_tags : [</tag1>],
            fragment_size: 100,  #匹配片段长度
            number_of_fragments: 5,  #匹配片段数
            no_match_size: 0,  #无匹配情况下文本长度
        }
        field1 : {}
    }
}

聚合查询

请求体

curl -XGET http://localhost:9200/索引/类型/_search -d
{
	size:0, #设置查询结果集数目为0提高聚合查询速度
	query:查询表达式,
	aggs:聚合表达式,
}

聚合表达式

{
	聚合名1:{
		聚合方法:{field:字段}
		
		global:{}, #声明在全局桶下聚合(聚合运算基于全部文档)
		aggs:嵌套聚合表达式(仅桶类聚合下面可以增加嵌套聚合)
	},

	...
}

聚合构成
一个聚合的每个 层级 都可以有多个度量或桶

  • Buckets桶 - 足特定条件的文档的集合
  • Metrics指标 - 桶内的文档进行统计计算

聚合方法

  • Buckets桶类(输出桶集,桶内包含统计量)
    • terms 唯一词项分桶(俗称facet特性,高效统计指定层面下各类目约束下的统计量)
    • histogram 数值序列分桶
      • interval: 间隔数值
    • date_histogram 时间序列分桶
      • interval: year|quarter|month|day ...
      • format: yyyy-MM-dd
  • Metrics指标类(输出度量值)
    • min 最小字段值
    • max 最大字段值
    • avg 平均字段值
    • sum 求和字段值
    • stats 字段统计值汇总(包括count、min、max、avg、sum)
    • extended_stats 拓展的字段统计值汇总(stats基础上追加 sum_of_squares平方和、variance方差、std_deviation标准差)

分桶聚合通用参数

  • min_doc_count 指定为0则强制空桶也被返回
  • extended_bounds 扩展分桶的上下限

GEO查询

距离算法distance_type

  • arc 最慢但最精确(球体地球角度)
  • plane 精度性能居中(平坦地球角度)
  • sloppy_arc 最快但最误差(比arc快四五倍,精度99.9%)

圈过滤

{
    geo_distance:{
        distance:1km,
        distance_type:距离算法,
        location位置字段:{
            lon:对比经度
            lat:对比纬度
        }
    }
}

环过滤

{
    geo_distance_range:{
        gte:1km,内径
        lte:1km,外径
        distance_type:距离算法,
        location位置字段:{
            lon:对比经度
            lat:对比纬度
        }
    }
}

排序

{
    _geo_distance:{
        location位置字段:{
            lat:对比纬度,
            lon:对比经度
        },
        nested_path:可选的nest路径,
        order:desc|asc,
        unit:km,
        distance_type:距离算法
    }
}

返回结果中,每个条目的sort字段首个值即为相对距离/m

完整示例

{
    index: my_index,
    body: {
        query: {
            bool: {
                must: [ #评分模式的搜搜匹配
                    {match: {字段: 值}},
                    ...
                    {nested: {
                        path:上级字段,
                        query: {
                            bool: {
                                must: [
                                    {match: {上级字段.该级字段: 值}},
                                    ...
                                ]
                            }
                        }
                    }}
                ],
                filter: [ #不评分模式的过滤
                    {term: {字段:值}},
                    {range: {字段:{gte:最小值,lt:最大值}}},
                    ...
                    {
                        geo_distance:{
                            distance:1km,
                            distance_type:距离算法,
                            location位置字段:{
                                lon:对比经度
                                lat:对比纬度
                            }
                        }
                    }
                ],
            }
        },
        
        from: 100,
        
        size: 50,

        sort: [
            {排序字段: {order: desc}},
            ...
            {_geo_distance:{
                location位置字段{
                    lon:对比经度
                    lat:对比纬度
                },
                order:asc,
                unit:km,
                distance_type:距离算法
              }
            }
        ],
        
          highlight: {
            {
                fields : {
                    myField: {
                        pre_tags : [<tag1>],
                        post_tags : [</tag1>],
                        fragment_size: 100,  #匹配片段长度
                        number_of_fragments: 5,  #匹配片段数
                        no_match_size: 0,  #无匹配情况下文本长度
                    }
                }
            }
          },

        aggs: {
            聚合名: {
                term: {field: 字段名},
                ...
                aggs: {
                    mySum: {sum: {field:字段名}}
                }
            },
            ...
        },
    }
}

数据建模

关联关系设计

  • 应用层关联 mapping:独立 优缺点:类似于关系型数据库的标准设计,查询性能较差 查询:人工组织关联查询
  • 非规范化文档(适用单个子对象) mapping:共用(子对象:object类型字段,也是字段默认自动映射类型) 文档结构:冗余文档结构,被扁平化为键值结构 优缺点:查询效率较高,但是文档索引过大 查询:使用点语法查询子对象字段
  • 嵌套对象文档(适用多个子对象) mapping:共用(子对象:nested类型字段) 文档结构:冗余文档结构,每一个嵌套对象都会被索引为一个隐藏的独立文档 优缺点:查询效率较高,但是文档索引过大 查询:使用nested语法查询子对象字段
  • 父子关系文档 mapping:独立 文档结构:父对象和子对象都是完全独立的文档 优缺点:索引效率较高,但是查询效率较低 查询:使用has_child、has_parent语法查询父子对象字段

扩容设计

  • 待定

© 著作权归作者所有

麦拂沙
粉丝 22
博文 120
码字总数 109619
作品 1
海淀
高级程序员
私信 提问
Java搜索引擎选择: Elasticsearch与Solr(转)

Elasticsearch简介 Elasticsearch是一个实时的分布式搜索和分析引擎。它可以帮助你用前所未有的速度去处理大规模数据。 它可以用于全文搜索,结构化搜索以及分析,当然你也可以将这三者进行组...

easonjim
2017/11/13
0
0
全文搜索引擎选 ElasticSearch 还是 Solr?

点击上方“芋道源码”,选择“设为星标” 做积极的人,而不是积极废人! 来源:http://t.cn/Ebgm7sn 什么是全文搜索 为什么要用全文搜索搜索引擎 Lucene,Solr,ElasticSearch ? Elasticsea...

芋道源码
04/03
0
0
Elasticsearch初探(1)——基本介绍与环境搭建

版权声明:本文版权归Jitwxs所有,欢迎转载,但未经作者同意必须保留原文链接。 https://blog.csdn.net/yuanlaijike/article/details/82966110 一、Elasticsearch简介 1.1 什么是Elasticsear...

Jitwxs
2018/10/08
0
0
搜索引擎选择: Elasticsearch与Solr

搜索引擎选型调研文档 Elasticsearch简介* Elasticsearch是一个实时的分布式搜索和分析引擎。它可以帮助你用前所未有的速度去处理大规模数据。 它可以用于全文搜索,结构化搜索以及分析,当然...

开源中国首席码农
2016/11/15
1K
4
Elastic Search原理简述

一、Elastic Search概述: 1.1 Elastic Search 简介 Elastic Search(ES)是一个基于Lucene构建的开源、分布式、RESTFul接口全文搜索引擎。ES还是一个分布式文档库,其中每个字段均是被索引的...

zhglance
02/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

spring cloud

一、从面试题入手 1.1、什么事微服务 1.2、微服务之间如何独立通讯的 1.3、springCloud和Dubbo有哪些区别 1.通信机制:DUbbo基于RPC远程过程调用;微服务cloud基于http restFUL API 1.4、spr...

榴莲黑芝麻糊
4分钟前
0
0
Executor线程池原理与源码解读

线程池为线程生命周期的开销和资源不足问题提供了解决方 案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。 线程实现方式 Thread、Runnable、Callable //实现Runnable接口的...

小强的进阶之路
昨天
6
0
maven 环境隔离

解决问题 即 在 resource 文件夹下面 ,新增对应的资源配置文件夹,对应 开发,测试,生产的不同的配置内容 <resources> <resource> <directory>src/main/resources.${deplo......

之渊
昨天
8
0
详解箭头函数和普通函数的区别以及箭头函数的注意事项、不适用场景

箭头函数是ES6的API,相信很多人都知道,因为其语法上相对于普通函数更简洁,深受大家的喜爱。就是这种我们日常开发中一直在使用的API,大部分同学却对它的了解程度还是不够深... 普通函数和...

OBKoro1
昨天
7
0
轻量级 HTTP(s) 代理 TinyProxy

CentOS 下安装 TinyProxy yum install -y tinyproxy 启动、停止、重启 # 启动service tinyproxy start# 停止service tinyproxy stop# 重启service tinyproxy restart 相关配置 默认...

Anoyi
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部