Elasticsearch

2019-10-27  本文已影响0人  djm猿

1 Elasticsearch 简介

1.1 什么是 Elasticsearch?

Elasticsearch是一个基于 Apache Lucene 的开源搜索引擎。无论在开源还是专有领域,Lucene 可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。

特点:

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

1.2 Elasticsearch 应用场景

1.3 Elasticsearch 使用案例

1.4 同类产品

Solr、ElasticSearch、Hermes:

Solr、ES 区别:

2 Elasticsearch 安装部署

2.1 单机部署

解压

[djm@hadoop102 software]$ tar -vzxf elasticsearch-6.3.1.tar.gz -C /opt/module/

设置访问 IP

vim config/elasticsearch.yml
network.host: 0.0.0.0

[max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

sysctl -w vm.max_map_count=262144

启动和停止

# 前台启动
[djm@hadoop102 bin]$ ./elasticsearch
# 后台启动
[djm@hadoop102 bin]$ ./elasticsearch -d

2.2 集群部署

修改 elasticserach.yml 文件

#集群名称
cluster.name: my-application
#节点名称(不能重复)
node.name: node-2
#指定了该节点可能成为 master 节点,还可以是数据节点
node.master: true
node.data: true
#数据的默认存放路径(自定义)
path.data: /opt/module/elasticsearch-6.3.1/data
#日志的默认存放路径 
path.logs: /opt/module/elasticsearch-6.3.1/logs 
#允许外网访问
network.host: 0.0.0.0
#对外提供服务的端口
http.port: 9200 
#9300为集群服务的端口 
transport.tcp.port: 9300
#集群个节点IP地址,也可以使用域名,需要各节点能够解析 
discovery.zen.ping.unicast.hosts: ["hadoop102", "hadoop103", "hadoop104"]
#为了避免脑裂,集群节点数最少为 半数+1
discovery.zen.minimum_master_nodes: 2 

解压 head、node

[djm@hadoop102 ~]$ tar -zxvf    node-v9.9.0-linux-x64.tar.gz
[djm@hadoop102 ~]$ unzip elasticsearch-head-master.zip

配置 Node 环境变量

#NODE_HOME
export NODE_HOME=/opt/module/node-v9.9.0
export PATH=$PATH:$NODE_HOME/bin

测试环境变量

[djm@hadoop102 ~]$ node -v
[djm@hadoop102 ~]$ npm -v

安装 grunt,进入到 head 目录

[djm@hadoop102 elasticsearch-head-master]$ npm install -g grunt-cli
[djm@hadoop102 elasticsearch-head-master]$ npm install

修改 elasticsearch.yml 文件,添加如下内容:

http.cors.enabled: true
http.cors.allow-origin: "*"

修改 Gruntfile.js,找到 connect 属性,新增 hostname: ’*’

connect: {
    server: {
        options: {
            hostname: '*',
            port: 9100,
            base: '.',
            keepalive: true
        }
    }
}

启动

# 前台启动
[djm@hadoop102 elasticsearch-head-master]$ grunt server
# 后台启动
[djm@hadoop102 elasticsearch-head-master]$ nohup grunt server &exit

2.3 Elasticsearch 操作工具

3 Elasticsearch API

3.1 Mapping

定义数据库中的表的结构的定义,通过 mapping 来控制索引存储数据的设置

获取 mapping

GET /djm/_mapping

Dynamic Mapping

JSON类型 es 类型
null 忽略
boolean boolean
浮点类型 float
整数 long
object object
array 由第一个非 null 值的类型决定
string 匹配为日期设为 date 类型(默认开启),数字设为 float 或 long 类型(默认关闭),设为 text 类型,并附带keyword的子字段

mapping 中的字段类型一旦设定后,禁止修改

dynamic设置

PUT my_index
{
    "mappings": {
        "doc": {
            "dynamic": false,
            "properties": {
                "user": {
                    "properties": {
                        "name": {
                            "type": "text"
                        },
                        "social_networks": {
                            "dynamic": true,
                            "properties": {}
                        }
                    }
                }
            }
        }
    }
}

copy_to 将该字段的值复制到目标字段,实现 _all 的作用,不会出现在 _source 中,只用来搜索

PUT my_index
{
    "mappings": {
        "doc": {
            "properties": {
                "frist_name": {
                    "type": "text",
                    "copy_to": "full_name"
                },
                "last_name": {
                    "type": "text",
                    "copy_to": "full_name"
                },
                "full_name": {
                    "type": "text"
                }
            }
        }
    }
}

Index 属性,控制当前字段是否可以被索引,默认为 true

PUT my_index
{
    "mappings": {
        "doc": {
            "properties": {
                "cookie": {
                    "type": "text",
                    "index": false
                }
            }
        }
    }
}

Index_options 用于控制倒排索引记录的内容

3.2 Document

索引一个文档

PUT {index}/{type}/{id}
{
    "": ""
}

使用自己的 ID

PUT /{index}/{type}/{id}
{
    "field": "value",
    ...
}

例如我们的索引叫做 website,类型叫做 blog,我们选择的 ID 是123,那么这个索引请求就像这样:

PUT /website/blog/123
{
    "title": "My first blog entry",
    "text": "Just trying this out...",
    "date": "2014/01/01"
}
响应指出请求的索引已经被成功创建,这个索引中包含_index、_type和_id元数据,以及一个新元素:_version
每个文档都有版本号,每当文档发生变化时都会使_version发生变化

自增 ID

POST /website/blog/
{
    "title": "My second blog entry",
    "text": "Still trying this out...",
    "date": "2014/01/01"
}

检索文档

GET /website/blog/123?pretty

检索文档的一部分

#_source只包含title、text字段
GET /website/blog/123?_source=title,text
#仅返回_source
GET /website/blog/123/_source

检索多个文档

POST /_mget
{
    "docs": [
        {
            "_index": "website",
            "_type": "blog",
            "_id": 2
        },
        {
            "_index": "website",
            "_type": "pageviews",
            "_id": 1,
            "_source": "views"
        }
    ]
}

如果检索的文档在同一个 _index 中(甚至在同一个 _type 中),可以在 URL 中定义一个默认的 _index 或者_index/_type

POST /website/blog/_mget
{
    "ids": [
        "2",
        "1"
    ]
}

更新文档

POST /website/blog/123
{
    "title": "My first blog entry",
    "text": "I am starting to get the hang of this...",
    "date": "2014/01/02"
}

局部更新

POST /website/blog/123/_update
{
    "doc": {
        "tags": [
            "testing"
        ],
        "views": 0
    }
}

删除文档

DELETE /website/blog/123

批量插入

POST test_search_index/doc/_bulk
{
    "index": {
        "_id": 1
    }
}
{
    "username": "alfred way",
    "job": "java engineer",
    "age": 18,
    "birth": "1991-12-15",
    "isMarried": false
}
{
    "index": {
        "_id": 2
    }
}
{
    "username": "alfred",
    "job": "java senior engineer and java specialist",
    "age": 28,
    "birth": "1980-05-07",
    "isMarried": true
}
{
    "index": {
        "_id": 3
    }
}
{
    "username": "lee",
    "job": "java and ruby engineer",
    "age": 22,
    "birth": "1985-08-07",
    "isMarried": false
}
{
    "index": {
        "_id": 4
    }
}
{
    "username": "lee junior way",
    "job": "ruby engineer",
    "age": 23,
    "birth": "1986-08-07",
    "isMarried": false
}

3.3 Search API(URI)

GET /_search #查询所有索引文档

GET /my_index/_search #查询指定索引文档

GET /my_index1,my_index2/_search #多索引查询

GET /my_index/_search?q=user:alfred #指定字段查询

GET /my_index/_search?q=keyword&df=user&sort=age:asc&from=4&size=10&timeout=1s

term 与 phrase

泛查询

指定字段

Group

布尔操作符

范围查询

通配符查询

正则表达式

模糊匹配 fuzzy query

近似度查询 proximity search

3.4 Search API(Request Body Search)

Match Query 对字段作全文检索,最基本和常用的查询类型

GET test_search_index/_search
{
    "profile": true,
    "query": {
        "match": {
            "username": "alfred way"
        }
    }
}

通过 operator 参数可以控制单词间的匹配关系,可选项为 or 和 and

GET test_search_index/_search
{
    "query": {
        "match": {
            "username": {
                "query": "alfred way",
                "operator": "and"
            }
        }
    }
}

4 Elasticsearch 数据结构

核心数据类型

复杂数据类型

地理位置数据类型

专用类型

1、创建 mapping

PUT my_index
{
    "mappings": {
        "doc": {
            "properties": {
                "username": {
                    "type": "text",
                    "fields": {
                        "pinyin": {
                            "type": "text"
                        }
                    }
                }
            }
        }
    }
}

2、创建文档

PUT my_index1/doc/1
{
    "username": "haha heihei"
}

3、查询

GET my_index/_search
{
    "query": {
        "match": {
            "username.pinyin": "haha"
        }
    }
}

Dynamic Mapping

PUT /test_index/doc/1
{
    "username": "alfred",
    "age": 1
}
age自动识别为long类型,username识别为text类型
PUT test_index/doc/1
{
    "username": "samualz",
    "age": 14,
    "birth": "1991-12-15",
    "year": 18,
    "tags": [
        "boy",
        "fashion"
    ],
    "money": "100.1"
}
birth自动识别为日期。。。。

自定义日期识别格式

PUT my_index
{
    "mappings": {
        "doc": {
            "dynamic_date_formats": [
                "yyyy-MM-dd",
                "yyyy/MM/dd"
            ]
        }
    }
}

关闭日期自动识别

PUT my_index
{
    "mappings": {
        "doc": {
            "date_detection": false
        }
    }
}

字符串是数字时,默认不会自动识别为整形,因为字符串中出现数字时完全合理的,Numeric_datection 可以开启字符串中数字的自动识别

PUT my_index
{
    "mappings": {
        "doc": {
            "numeric_datection": true
        }
    }
}

5 Elasticsearch 原理

5.1 Elasticsearch 数据存储

5.1.1 Elasticsearch 存储方式

面向文档:

Elasticsearch 是面向文档的,这意味着它可以存储整个对象或文档,它在存储的时候还会对文档进行索引,使文档的内容可以被搜索,在 Elasticsearch 中,可以对文档进行索引、搜索、排序、过滤,这就是 Elasticsearch 能够执行复杂的全文检索的原因。

JSON:

Elasticsearch 使用 JSON,作为文档序列化格式,JSON 目前已成为 NoSQL 领域的标准格式,简洁容易阅读,并且对 JSON 做索引比在表结构中做索引容易的多。

5.1.2 Elasticsearch 存储结构

[图片上传失败...(image-575404-1572113601393)]

POST djm/doc
{
    "name": "zhangsan",
    "age": 10
}

名称解释:

1、索引 Index

2、类型 type

3、字段 field

4、文档 document

5.2 Elasticsearch 搜索原理

5.2.1 正排索引和倒排索引

正排索引:记录文档Id到文档内容、单词的关联关系

倒排索引:记录单词到文档id的关联关系

5.2.2 分词

分词是指将文本转换成一系列单词(term or token)的过程,也可以叫做文本分析

Elasticsearch 自带的分词器

分词器(Analyzer) 特点
Standard(es默认) 支持多语言,按词切分并做小写处理
Simple 按照非字母切分,小写处理
Whitespace 按照空格来切分
Stop 去除语气助词,如the、an、的、这等
Keyword 不分词
Pattern 正则分词,默认\w+,即非字词符号做分割符
Language 常见语言的分词器(30+)

5.2.3 IK 分词器

将 ik 解压到 elasticsearch-6.3.1\plugins 并重命名为 analysis-ik,即可加载 ik 分词器

IK 提供了两个分词算法 ik_smart 、ik_max_word,其中 ik_smart 为最少切分,ik_max_word 为最细粒度划分

#Request
POST _analyze
{
    "tokenizer": "ik_smart",
    "text": "我是程序员"
}
#Response
{
    "tokens": [
        {
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        },
        {
            "token": "是",
            "start_offset": 1,
            "end_offset": 2,
            "type": "CN_CHAR",
            "position": 1
        },
        {
            "token": "程序员",
            "start_offset": 2,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        }
    ]
}
#Request
POST _analyze
{
    "tokenizer": "ik_max_word",
    "text": "我是程序员"
}
#Response
{
    "tokens": [
        {
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        },
        {
            "token": "是",
            "start_offset": 1,
            "end_offset": 2,
            "type": "CN_CHAR",
            "position": 1
        },
        {
            "token": "程序员",
            "start_offset": 2,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "程序",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "员",
            "start_offset": 4,
            "end_offset": 5,
            "type": "CN_CHAR",
            "position": 4
        }
    ]
}

5.3 集群操作原理

一个节点就是一个 Elasticsearch 实例,而一个集群是由多个节点组成,它们具有相同的集群名称,它们协同工作,分享数据和负载,当加入新的节点或者删除一个节点时,集群就会感知到,并平衡数据

5.3.1 属于介绍

节点 node

分片和复制 shards & replias

集群健康有三种状态:

颜色 意义
green 所有主要分片和复制分片都可用
yellow 所有主要分片可用,但不是所有复制分片都可用
red 不是所有的主要分片都可用

故障转移

5.3.2 路由

当你索引一个文档,它被存储在单独一个主分片上,Elasticsearch 是如何知道文档属于哪个分片的呢?当你创建一个新文档,它是如何知道是应该存储在分片 1 还是分片 2 上的呢?

进程不能是随机的,因为我们将来要检索文档

算法决定:

shard = hash(routing) % number_of_primary_shards

routing 值是一个任意字符串,它默认是 _id 但也可以自定义

为什么主分片的数量只能在创建索引时定义且不能修改?

如果主分片的数量在未来改变了,所有先前的路由值就失效了,文档也就永远找不到了

所有的文档 API(get、index、delete、bulk、update、mget)都接收一个 routing 参数,它用来自定义文档到分片的映射,自定义路由值可以确保所有相关文档——例如属于同一个人的文档——被保存在同一分片上

5.3.3 操作数据节点工作流程

[图片上传失败...(image-4aef1e-1572113601393)]

5.3.4 检索流程

[图片上传失败...(image-f07c-1572113601393)]

对于读请求,为了平衡负载,请求节点会为每个请求选择不同的分片——它会循环所有分片副本

可能的情况是,一个被索引的文档已经存在于主分片上却还没来得及同步到复制分片上,这时复制分片会报告文档未找到,主分片会成功返回文档,一旦索引请求成功返回给用户,文档则在主分片和复制分片都是可用的

上一篇 下一篇

猜你喜欢

热点阅读