ES学习-01

459 阅读12分钟

版本选择

  • 见官网 www.elastic.co/cn/support/… 可以查看各个版本的差别
  • 尽量选择各个组件都比较切合的版本,这里选择7.17版本,需要jdk11支持,同时可以使用logstash等组件

Elastic组件

  • Elastic中有三个基本组件,组合成为ELK,即ElasticSearch、logstash、Kibana。
  • ElasticSearch:搜索引擎
  • Logstash:提供数据转换功能,可将不同的数据源转换为ES数据并导入数据库
  • Kibana:提供ES的可视化操作和监控界面等

基本组件

index(索引)

  • ES会索引所有的字段,经过处理后写入到一个反向索引中,查询数据时,直接查询该索引
  • ES数据管理的顶层单位为Index,相当于table

document(文档)

  • Index中单条记录叫做document,许多条document构成了一个Index
  • 同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。

Type

  • Document可以进行分组,是逻辑分组,用来过滤Document
  • 不同的Type应该有相同的结构,例如,id不能在一个分组中为字符串,在另一个分组中是整型
  • 根据规划,Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。

关系型数据库和ES结构对比

关系型数据库ES备注
columnfield
rowdocument
indextable
schemaimplicitES并没有像关系型数据库那样有schema这样的数据库标识

:star2:schema和database的区别

  • 在mysql中schema和database是同一个东西,oracle中schema等同于命名空间
  • schema和user以及role结合用来控制权限

安装和启动

  1. 需要有jdk8的环境
  2. 从官网下载对应版本的包,解压即可
  3. 执行bin目录下的elasticSearch即可启动,或通过./elasticsearch -d后台运行,日志可通过log/elasticsearch.log查看
  4. 启动后,访问localhost:9200即可查看是否启动成功

启动可能用到的问题

不能使用root用户运行

  • 不能使用root用户运行
  • 需要自己创建一个新的用户来启动ES,具体如下:
groudadd 分组名
useradd 用户名 -g 分组名 -p 密码

file descriper too low

  • file descriper too low,即文件描述符设置较低,导致无法正常运行,此时需要修改服务器的文件描述符的数量,具体如下
vim /etc/security/limits.conf
  • limits.conf最后,追加以下内容, *表示所有用户,可以根据需要配置不同的用户
  • 重启服务器后,生效
* soft nofile 10000
* hard nofile 10000

vm.max_map_count is too low

  • vm.max_map_count is too low
  • 修改、/ect/sysctl.conf文件,追加vm.max_map_count=10000即可

java.net.UnknownHostException: geoip.elastic.co

  • 不影响运行和使用
  • 最新版本默认会去官网下载ip的geo信息,可以通过配置ingest.geoip.downloader.enable:false来配置,不自动下载。

配置文件

  • elasticSearch的配置文件位置在config目录下,elasticSearch.yml
  • 常用配置项
# 设置host,用于外部访问es的ip,端口号默认为9200
network.host: 127.3.2.1
http.port: 9200
# 节点名称,可以不写
node.name: node-1
# 集群节点,可以不写
cluster.initial_master_nodes: ['node-1']
# 设置不自动下载ip的geo信息,不配置可能控制台会出现网络连接异常问题,虽然不会影响运行和使用
ingest.geoip.downloader.enabled: false

# 如果索引不存在,是否自动创建索引,如果为false,则创建文档时,如果索引不存在,则会报错
action.auto_create_index: false

快速开始

创建文档

 curl -X POST/PUT 'http://127.0.0.1:9200/index/doc/1' -H 'Content-Type: application/json' -d '{ "name": "柯南小海盗", "age": 17,"email": "knxhd@knxhd.com","sex": "男","enable": true}'
  • index:索引名,如果数据库没有,默认会自动创建,可以通过action.auto_create_index: false进行设置
  • doc:索引类型,必填,在7.X版本的ES中,一个索引仅仅能创建一个type
  • 1:文档的ID,唯一标识,可以不填,不填则会自动创建ID,如果重复创建,则会覆盖原来的数据
  • 如果不写ID,则请求类型必须为POST,因此为统一格式,一般新增建议都使用POST形式
  • pretty表示会格式化返回的结果,为了方便查看数据
  • 返回结果
{
  "_index" : "twitter",
  "_type" : "tweet",
  "_id" : "KWxMXoIBYDuUCopKeOMq",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 2
}
  • result为执行操作的类型,即created、updated、deleted等
  • _version:表示版本,可用于控制并发和事务
  • 返回结果中 _开发头的表示es的元数据,也就是默认属性

批量操作

  • 批量创建文档,使用_bulk接口实现,请求方式:POST
  • 请求类型和单个类似,需要传索引和文档类型等
  • 基本格式
{action: {metadata}} \n
{request body} \n
{action: {metadata}} \n
{request body} \n
  • action表示操作类型,即create、index、update、delete
  1. create: 创建文档,如果文档存在,则抛出异常
  2. index:创建文档,如果存在,则覆盖
  3. update:更新文档
  4. delete:删除文档
  • metadata表示文档的元数据,即
  • _index:所属索引
  • _type:索引类型
  • _id:文档ID
  • 元数据可以写在url中,即 /index/doc/_bulk
  • request body为要创建的文档对象
{"create":{}}
{"serviceid": 1,"service": "VIDEO_SEARCH_SERVICE","className": "com.hisense.keylab.semantic.service.SAVODSearchService","not": ""}
{"create":{}}
{"serviceid": 2,"service": "WEATHER_SEARCH_SERVICE","className": "com.hisense.keylab.semantic.service.SAWeatherSearchService","not": ""}
// 这里有个空行,匹配操作需要结尾为换行符

批量删除文档

curl --location --request POST 'http://127.0.0.1:9200/hiservice/_bulk' \
--header 'Content-Type: application/json' \
--data-raw '{"delete":{"_index":"hiservice", "_id": 10}}
  • 批量删除数据时,需要传入要删除的文档ID,否则会抛出Validation Failed: 1: id is missing异常

批量更新文档

curl --location --request POST 'http://127.0.0.1:9200/hiservice/_bulk' \
--header 'Content-Type: application/json' \
--data-raw '{"update":{"_index": "hiservice","_type": "_doc", "_id": "2ODM3YIBlOfFpc05V8IW"}}
{"doc": {"serviceid": 1,"service": "VIDEO_SEARCH_SERVICE","className": "com.hisense.keylab.semantic.service.SAVODSearchService","not": "ddfcfcr"}}

  • request body中的doc为固定写法,不能进行省略

删除索引

  • 根据ID进行删除,URL和新增相同,只不过需要请求类型为DELETE
  • 利用接口_delete_by_query删除数据
  • 根据接口_bulk删除文档

根据ID删除数据

curl --location --request DELETE 'http://127.0.0.1:9200/index/doc/1?pretty'

根据参数删除数据

修改索引

  • 方式一:全覆盖形式,使用新增索引相同的命令即可,ID为相同的
  • 方式二:修改部分字段,使用_update接口,请求方式为POST

全覆盖修改

curl --location --request PUT 'http://127.0.0.1:9200/index/doc/1?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "江户川柯南",
    "age": 7,
    "email": "kenan@knxhd.com",
    "sex": "男",
    "enable": true
}'
  • --header和-H等同

  • --data-raw与-d等同

  • --request和-X等同

  • 返回结果中_version会增加,类似于版本号,用于版本控制

返回结果为:

{
    "_index": "index",
    "_type": "doc",
    "_id": "1",
    "_version": 3,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 2
}

修改部分数据

  • 此时只会更新name的值,其中,参数doc为固定写法,只需要将要修改的数据放到doc中即可
curl --location --request POST 'http://127.0.0.1:9200/index/doc/1/_update' \
--header 'Content-Type: application/json' \
--data-raw '{
    "doc" : {
        "name" : "柯南小海盗"
    }
}'

查询索引

  • ES有两种查询机制,即评分查询和不评分查询。评分查询会根据查询条件通过评分逻辑对结果进行评分,并安装评分从高到低返回结果
  • 方式一:通过ID查询
  • 方式二:通过_search接口查询,详情_search
  • 方式三:通过_sql接口查询

根据ID查询

curl -X GET  'http://127.0.0.1:9200/index/doc/1?pretty'

_search接口

  • 请求方式:POST
  • 基本格式:/index/index_type/_search,index:索引(可选) index_type:索引类型(可选)
  • 可通过url传参和request body两种方式,详细细节见_search接口
:one: 查询全部数据
curl --location --request GET 'http://127.0.0.1:9200/hiservice/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "match_all": {}
    },
    "sort": {
        "serviceid": "ASC"
    }
}'

sort表示排序,key为排序字段,value为排序类型,即desc(倒序)、asc(正序)

:two: 查询部分字段
curl --location --request GET 'http://127.0.0.1:9200/hiservice/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "match_all": {}
    },
    "sort": {
        "serviceid": "ASC"
    },
    "_source": false,
    "fields": ["service", "className"]
}'
  • fields用来表示要返回的字段
  • _source表示是否显示源数据,如果为true,则既返回要查询的字段,又会返回原数据全部字段
  • _source=true,返回值为:
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": null,
        "hits": [
            {
                "_index": "hiservice",
                "_type": "_doc",
                "_id": "2eDM3YIBlOfFpc05V8Ig",
                "_score": null,
                "_source": {
                    "serviceid": 2,
                    "service": "WEATHER_SEARCH_SERVICE",
                    "className": "com.hisense.keylab.semantic.service.SAWeatherSearchService",
                    "not": ""
                },
                "fields": {
                    "service": [
                        "WEATHER_SEARCH_SERVICE"
                    ],
                    "className": [
                        "com.hisense.keylab.semantic.service.SAWeatherSearchService"
                    ]
                },
                "sort": [
                    2
                ]
            }
        ]
    }
}
  • 这里的_source为原数据,fields为特定字段返回的数据
  • _source为false时,则没有_source这个字段
:three: 范围查询
  • 范围查询使用字段`range``
  • gte:表示大于等于
  • gt:大于
  • lt:小于
  • lte:小于等于
  • 根据数字范围查询
curl --location --request POST 'http://127.0.0.1:9200/hi_type/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "range": {
            "ID": {
                "gte": 2,
                "lte": 10
            }
        }
    }
}'
  • 根据日期范围查询
{
    "query": {
        "range": {
            "updatetime": {
                "gte": "2014-03-06 18:24:23",
                "lt": "2014-03-16 15:40:43"
            }
        }
    }
}
  • 查询字段updatetime很有可能查询后为空,这是由于分词策略导致,此时,将查询字段修改为updatetime.keyword即可
:four: 联合查询

使用bool可以实现联合查询,详情可见_search

:five: 分页查询
  • 分页查询使用参数fromsize设置当前页和每页大小,from从0开始
curl --location --request POST 'http://localhost:9200/hinickname/h1i/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
    "from": 1,
    "size": 10
}'
:six: 多索引和多类型搜索
  • 使用_search搜索时,默认会对所有的索引进行搜索,包括系统提供的索引,这样可能会影响效率,同时也会搜索出不需要的数据,可以在路径中定义搜索的索引和类型
  • 方式一:/index/_search 在index索引下查询,支持模糊搜索,例如:/in*/_search 查询索引in开头
  • 方式二:/index/doc/_search 在index索引中doc类型下查询
  • 方式三:/index,index2/_search 在index和index2两个索引下查询
  • 方式四:/index,index2/doc,doc1/_search 在index和index2两个索引下查询doc,doc1两个类型的数据
  • 方式五:/_all/doc1,doc2/_search 查询所有索引中doc1,doc2类型的数据

ES配置

配置文件

  • es默认配置文件在config目录下,可以通过ES_PATH_CONF进行配置。配置方式有两种

  1. 启动时,通过参数配置

    ES_PATH_CONF=/path/to/my/config ./bin/elasticsearch
    
  2. 在环境变量中进行配置

路径配置

path:
 data: /var/data/elasticsearch
 log: /var/log/elasticsearch
  • data路径下的数据不能通过简单的赋值粘贴来完成数据备份

集群设置

cluster.name: custom
node.name: node1
network.host: 192.168.1.10
  • 默认集群名称为elasticsearch
  • node.name用来设置节点名称
  • network.host用来设置回环地址,默认可以通过localhost/127.0.0.1进行访问

集群节点设置

discovery.seed_hosts:
   - 192.168.1.10:9300
   - 192.168.1.11 
   - seeds.mydomain.com 
   - [0:0:0:0:0:ffff:c0a8:10c]:9301 
  • discovery.seed_hosts用来设置集群模式下的节点有哪些,配置支持ip、域名和vp6形式
  • 其中默认端口为9300,如果为9300则,端口可以不写

主节点设置

cluster.initial_master_nodes:
	 - master-node-a
    - master-node-b
    - master-node-c
  • 在集群启动时,会默认自动选择主节点,但是生产环境下,自动选择可能存在问题,可通过cluster.initial_master_nodes来设置主节点

审计日志

  • 可以通过审计日志记录对于安全性和权限相关的操作,例如:对用户和角色的增删改、认证失败、拒绝连接、数据拒绝操作等
  • 开启审计日志有两种方式
  1. 通过yml文件进行配置,设置xpack.security.audit.enabled为true即可
  2. 通过接口调用来进行修改
  • 不论是哪种方式修改,都需要所有节点都进行修改

审计日志设置

审计事件设置
xpack.security.audit.logfile.events.include
  • 通过设置可以设置哪些事件可以被记录,可以使用_all设置所有的事件,但是不推荐
  • 默认事件为:access_denied, access_granted, anonymous_access_denied, authentication_failed, connection_denied, tampered_request, run_as_denied, run_as_granted, security_config_change
  • 事件类型查看地址:www.elastic.co/guide/en/el…
xpack.security.audit.logfile.events.exclude
  • 排除审计事件设置
设置是否包含请求正文
xpack.security.audit.logfile.events.emit_request_body

用户验证

xpack.security.enabled: true
  • 在配置文件elasticsearch.yml中配置是否进行身份验证,开启身份验证后,启动ES
  • 通过命令elasticsearch-setup-passwords设置密码。密码设置方式有两种方式:
  1. ./elasticsearch-setup-passwords auto,自动生成一个随机密码
  2. ./elasticsearch-setup-passwords interactive,为每个用户设置特定的密码,密码设置后,如果再次设置密码,则会提示密码已设置成功
  • 修改密码后,可通过curl校验用户名和密码是否正确
curl -u elastic:elastic123@ http://127.0.0.1:9200

修改密码

已知当前密码
  • 采用CURL的形式调用修改密码的接口,需要校验原来的密码
 curl -XPOST -u elastic "127.0.0.1:9200/_security/user/elastic/_password" -H 'Content-Type: application/json' -d'{"password" : "elastic123456@"}'
忘记当前密码
  • 如果已经忘记了密码,则需要先关闭身份校验配置,即xpack.security.enabled: true

  • 在设置好密码后,可以看到生成的密码保持在索引.security-7中,可通过索引查看的接口,查询出多出的索引

  • 删除对应的索引,重新设置密码`

curl -XDELETE 127.0.0.1:9200/.security-7

同步数据

input {
	stdin {}
	jdbc {
		type => "jdbc"
		 # 数据库连接地址
		jdbc_connection_string => "jdbc:mysql://192.168.1.1:3306/TestDB?characterEncoding=UTF-8&autoReconnect=true""
		 # 数据库连接账号密码;
		jdbc_user => "username"
		jdbc_password => "pwd"
		 # MySQL依赖包路径;
		jdbc_driver_library => "mysql/mysql-connector-java-5.1.34.jar"
		 # the name of the driver class for mysql
		jdbc_driver_class => "com.mysql.jdbc.Driver"
		 # 数据库重连尝试次数
		connection_retry_attempts => "3"
		 # 判断数据库连接是否可用,默认false不开启
		jdbc_validate_connection => "true"
		 # 数据库连接可用校验超时时间,默认3600S
		jdbc_validation_timeout => "3600"
		 # 开启分页查询(默认false不开启);
		jdbc_paging_enabled => "true"
		 # 单次分页查询条数(默认100000,若字段较多且更新频率较高,建议调低此值);
		jdbc_page_size => "500"
		 # statement为查询数据sql,如果sql较复杂,建议配通过statement_filepath配置sql文件的存放路径;
		 # sql_last_value为内置的变量,存放上次查询结果中最后一条数据tracking_column的值,此处即为ModifyTime;
		 # statement_filepath => "mysql/jdbc.sql"
		statement => "SELECT KeyId,TradeTime,OrderUserName,ModifyTime FROM `DetailTab` WHERE ModifyTime>= :sql_last_value order by ModifyTime asc"
		 # 是否将字段名转换为小写,默认true(如果有数据序列化、反序列化需求,建议改为false);
		lowercase_column_names => false
		 # Value can be any of: fatal,error,warn,info,debug,默认info;
		sql_log_level => warn
		 #
		 # 是否记录上次执行结果,true表示会将上次执行结果的tracking_column字段的值保存到last_run_metadata_path指定的文件中;
		record_last_run => true
		 # 需要记录查询结果某字段的值时,此字段为true,否则默认tracking_column为timestamp的值;
		use_column_value => true
		 # 需要记录的字段,用于增量同步,需是数据库字段
		tracking_column => "ModifyTime"
		 # Value can be any of: numeric,timestamp,Default value is "numeric"
		tracking_column_type => timestamp
		 # record_last_run上次数据存放位置;
		last_run_metadata_path => "mysql/last_id.txt"
		 # 是否清除last_run_metadata_path的记录,需要增量同步时此字段必须为false;
		clean_run => false
		 #
		 # 同步频率(分 时 天 月 年),默认每分钟同步一次;
		schedule => "* * * * *"
	}
}

filter {
	json {
		source => "message"
		remove_field => ["message"]
	}
	# convert 字段类型转换,将字段TotalMoney数据类型改为float;
	mutate {
		convert => {
			"TotalMoney" => "float"
		}
	}
}
output {
	elasticsearch {
		 # host => "192.168.1.1"
		 # port => "9200"
		 # 配置ES集群地址
		hosts => ["192.168.1.1:9200", "192.168.1.2:9200", "192.168.1.3:9200"]
		 # 索引名字,必须小写
		index => "consumption"
		 # 数据唯一索引(建议使用数据库KeyID)
		document_id => "%{KeyId}"
	}
	stdout {
		codec => json_lines
	}
}