0x01:前言
最近漏洞盒子团队内部研究项目用到了海量数据查询,使用到了elasticsearch,由于目前网上资料较少,于是自己写了篇文章,记录在搭建的时候遇到的各种问题及解决办法,供君参考。
0x02:安装
首先安装es,他的的安装及常用的插件和配置很简单,这里简单说一下。
我是用的系统是在ubuntu12.04.05,es的唯一要求是安装较新版本的java。安装也相当简单,在官网下载deb安装包安装(www.elastic.co)。安装完后启动服务sudo service elasticsearch start访问localhost:9200 即可。
es配置文件在/etc/elasticsearch/elasticsearch.yml:
cluster.name: elasticsearch #此处是集群名
node.name: "Franz Kafka" #节点名
#node.data: true #指定该节点是否存储索引数据
#path.conf: /path/to/conf #设置配置文件的存储路径
#path.data: /path/to/data #设置索引数据的存储路径, 可以设置多个存储路径,用逗号隔开
#path.logs: /path/to/logs # 设置日志文件的存储路径
为了方便可视化管理es,安装es的head插件,进入安装目录下的bin目录:
sudo ./ plugin -install mobz/elasticsearch-head
访问http://localhost:9200/_plugin/head/
0x03:介绍
到这里,es的基本安装已经完成了,下面介绍下es的基本结构,方便大家对es有个基本的认识。
mysql ⇒数据库databases ⇒表tables ⇒ 行rows ⇒ 列columns
es ⇒索引indices ⇒ 类型types ⇒文档documents ⇒ 字段fields
es中所说的索引容易混淆,他有3种含义:
1. 索引(名词) 如上面类比,一个索引(index)就好比是mysql中的数据库,它是存储数据的地方。
2. 索引(动词)表示把一个文档存储到索引(名词)里。
3. 倒排索引 好比mysql为特定列增加一个索引。
和mysql类似,每个库都得有表,还有表的结构。es的每一个索引都有个类型,而每个type(类型)得有个mapping (映射)。mapping就像是mysql中的表结构,他将每个字段匹配为一种确定的数据类型(string,date等)。
你可以向已有映射中增加字段,但你不能修改它。如果一个字段在映射中已经存在,这可能意味着那个字段的数据已经被索引。如果你改变了字段映射,那已经被索引的数据将错误并且不能被正确的搜索到。
为了提高搜索的效率,es使用倒排索引来做全文搜索。通过analyzer(分词器)先把需要分析的文本,表征化为适合的term(词),然后标准化这些term,使他们容易被搜索到。(比如说模糊大小写,空格等等)
对于中文分词,ik插件无疑是比较好的一个选择。
下载ik:https://github.com/medcl/elasticsearch-analysis-ik
解压之后进入目录打包:
sudo mvn compile(需安装maven 第一次时间比较长 失败可以多试几次)
sudo mvn package
maven
执行完毕后会在当前目录下生成target/releases目录。
将其中的elasticsearch-analysis-ik-1.4.0.zip 拷贝到ES目录下新建的plugins/analysis-ik,并解压,没有这个目录可以自己建。将elasticsearch-analysis-ik目录中的config/ik 拷贝到ES的config目录。
打开config/elasticsearch.yml,在最后添加:
index:
analysis:
analyzer:
ik:
alias: [ik_analyzer]
type: org.elasticsearch.index.analysis.IkAnalyzerProvider
ik_max_word: #会将文本做最细粒度的拆分,穷尽各种可能的组合
type: ik
use_smart: false
ik_smart:
type: ik
use_smart: true
重启es,使ik分词器可用。
一个好的分词器,可以提高查询的效率、准确度和全面性。
由于es自带有默认的分词器,如果不需要使用,可以在建立mapping时声明。
"index" : "not_analyzed" 。
0x04:导入数据
关于导入数据。我这里使用的是logstash:
logstash的处理流程分只有三个阶段,但是拥有丰富的功能:
input->Filter-> Output
导入->处理->输出
能导入json,csv,xml等格式的数据,并且支持从其他数据库中导出数据。
logstash的filter也是非常的全面,比如其中的geoip可以直接,分析一个IP的经纬度,归属地等信息。
下面通过一个配置文件实例,来说容易遇到的问题:
input {
file {
path => "/home/freebuf/Desktop/free.json" #文件位置
start_position => "beginning"
}
}
filter {
json{
source => "message" #这必要的一个参数
}
mutate{
remove_field => ["path","message","host","@timestamp","@version"]
#去掉一些不想显示的字段
add_field => {"字段" => "值"}
#添加字段
}
}
output {
elasticsearch {
host => localhost
index => "database"
index_type => "data"
protocol => "http"
cluster => "yourclustername" ##如果你修改了集群名,此处要指定。
}
}
1、json格式一定要处理为以下格式,一个组数据一行:
{"USERID":"KAKAO","TITLE":BUF,"TEXT":"HI"}
{"USERID":"NACY","TITLE":FREE,"TEXT":"HELLO"}
2、如果导入数据时出错,再次导入时没有数据被索引,是因为此处的用户目录下的.sincedb*文件,因为每当导入一个文件时,最后一个字节处理保存在sincedb中。他是通过inode定期读取出来的文件,如果文件有相同的inode号,程序会认为是相同的文件。可以删除缓存文件,再导入。
通过logstash可以灵活的把数据导入到elasticsearch中。
0x05:查询
数据库最重要查询功能了,es中head插件自带的web界面查询限制颇多,使用不是很灵活,我们可以通过其自带的查询进行分析,写出自己想要查询语句。
head插件的数据浏览,是通配符匹配查询,下面是查询语句:
{"fields":["_parent","_source"], #查询元数据中的_source字段
"query":{"bool": # bool查询
{"must":[{"wildcard":{"EMAIL":"nicef*"}}], # 使用通配符,must表示必须匹配
"must_not":[],
"should":[]}},
"from":0,"size":50,"sort":[],"facets":{},"version":true} #最多显示50条数据。
如果使用了默认的分析器,@ #之类的特殊符号,会导致上面的语句查询之后,匹配不到数据:
{"query":{"bool":
{"must":[{"query_string":{"default_field":"data.EMAIL","query":"@163.com"}}],
"must_not":[],
"should":[]}},
"from":0,"size":10,"sort":[],"facets":{}}
使用字符串查询就可以查到特殊字符包括中文。
通过各种查询条件,可以灵活的匹配到所需的内容。
Pyes可以让你优雅的用Python使用ElasticSearch,他提供了丰富的API:
比如使用pyes.es.ES与es建立连接,pyes.managers管理整个es集群,还可以灵活的查询BoolQuery().add_should(TermQuery("fields", string));等等。
0x06:结语
elasticsearch作为时下流行的搜索引擎,拥有分布式的实时文件存储及强大的实时分析搜索,可以轻易扩展到上百台服务器,处理PB级数据,无需复杂的理论,值得拥有。
* 作者:漏洞盒子安全团队devil