大数据-es(elasticsearch)
elasticsearch是lucene作为核心的实时分布式检索,底层使用倒排索引实现。
倒排索引原理
原始数据
id 数据值
1 你好杯子东西
2 中国我爱
3 你杯子我
通过分词创建倒排索引
你 1[0] 3[0]
杯子 1[2] 3[1]
中国 2[0]
我 2[2] 3[3]
上述主键词也是有序的,值为主键词所在原始数据的id,[]内为词所在位置
检索时:提供检索词,基于主键词的有序性二分法进行定位,通过倒排索引的结果知道检索词对应的id,最终定位到原始数据中的数据值
安装
-
修改jdk1.8环境
安装jdk1.8
/ect/profile中的JAVA_HOME
修改以下配置文件中的JAVA_HOME
/opt/sxt/hbase-0.98/conf/hbase-env.sh
/opt/sxt/hadoop-2.6.5/etc/hadoop/hadoop-env.sh
/opt/sxt/hadoop-2.6.5/etc/hadoop/mapred-env.sh(直接注释)
/opt/sxt/hadoop-2.6.5/etc/hadoop/yarn-env.sh(直接注释)
-
安装es软件 tar -zxvf elasticsearch-2.4.5.tar.gz
-
配置集群 vim /opt/sxt/elasticsearch-2.4.5/config/elasticsearch.yml
Cluster.na (集群名)
Node.name:node1 (定义本节点名称)
Network.Host: 192.168.163.201 (本节点ip)
另外插入防脑裂配置(关闭多播,连接超时,单播配置)
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping_timeout: 120s
client.transport.ping_timeout: 60s
discovery.zen.ping.unicast.hosts: ["192.168.163.201","192.168.163.202", "192.168.163.203"]
-
复制到其他节点
scp -r /opt/sxt/elasticsearch-2.4.5 root@node1:/opt/sxt/
修改elasticsearch.yml文件,节点名与ip地址
-
修改elasticsearch的权限
useradd es
passwd es 在设置密码位123456
chown es:es -R /opt/sxt/elasticsearch-2.4.5
-
启动测试
不支持root启动,内部插件需要修改权限
切换用户 su es
切换至bin目录下 cd /opt/sxt/elasticsearch-2.4.5/bin
运行 ./elasticsearch -d (后台运行-d参数)
启动集群后需要等待一段时间,集群需要选举出主节点
注意时间同步
在非后台运行 ctrl + c 停止es运行
网络访问
http://node1:9200 或者 (http://node1:9200/_cluster/health?pretty)
命令
支持基于restful风格的http请求,返回json格式数据
请求地址192.168.163.201:9200/
使用curl命令 模拟http请求
普通命令
curl -XPUT http://192168.163.201:9200/索引库/类型/文档 -d 要传输的数据
请求的类型包括 GET(查询),PUT(修改),POST(创建),DELETE(删除),HADE(头信息)
-
创建索引库与删除索引库
curl -XPOST http://192168.163.201:9200/shsxt (PUT或POST)
curl -XDELETE http://192.168.163.201:9200/shsxt
-
创建文档(插入数据) 一般使用POST
指定文档id,可以使用POST和PUT ,(例子中文档id为01)
curl -XPOST http://192.168.163.201:9200/shsxt/xxx/01 -d '{"name":"xm", "age":25 ,"address":"bj"}'
不指定文档id,es自动创建,这种方式只能使用POST方式
curl -XPOST http://192.168.163.201:9200/shsxt/xxx -d '{"name":"xm", "age":25 ,"address":"bj"}'
-
更新文档 一般使用PUT
全局更新,将对应的01文档字段全部替换
curl -XPOST http://192.168.163.201:9200/shsxt/xxx/01 -d '{"name":"xh", "age":30}'
局部更新 使用_update参数,将重复字段修改,不存在字段添加
curl -XPUT http://192.168.163.201:9200/shsxt/xxx/01/_update '{"name":"xl" ,"class":6 }'
-
删除
curl -XDELETE http://192.168.163.201:9200/shsxt/xxx/01
curl -XDELETE http://192.168.163.201:9200/shsxt/xxx
curl -XDELETE http://192.168.163.201:9200/shsxt
curl -XDELETE http://192.168.163.201:9200
删除只会标记数据,后台一段时间后再实际删除
返回200 ok的状态码
-
普通查询
原始查询
curl -XGET http://192.168.163.201:9200/shsxt/xxx/01
美化查询
curl -XGET http://192.168.163.201:9200/shsxt/xxx/01?pretty
只查询数据 _source
curl -XGET http://192.168.163.201:9200/shsxt/xxx/01/_source?pretty
只查询数据中的指定字段 _source=name,age
curl -XGET http://192.168.163.201:9200/shsxt/xxx/01/_source=name,age
增加响应头信息 -i
curl -i -XGET http://192.168.163.201:9200/shsxt/xxx/01
查询所有数据 _search
curl -XGET http://192.168.163.201:9200/shsxt/xxx/_search
查询指定数据 _search
curl -XGET http://192.168.163.201:9200/shsxt/xxx/_search?q=name:xm
查询需要扩大范围则去掉小范围的uri即可
DSL查询命令
Domain Specific Language 特定领域查询
curl -XGET http://192.168.78.101:9200/shsxt/employee/_search -d '{内容}'
参数说明
-
query 查找
-
match完全匹配 ;must_not 相当于NOT
-
should相当于OR
-
multi_match 多字段匹配
-
bool 多条件查询
-
range范围
例子说明
-
定值查询
curl -XGET http://localhost:9200/shsxt/employee/_search?pretty -d '{
"query":
{"match":
{"last_name":"smith"}
}
}' -
多字段匹配值
curl -XGET http://localhost:9200/shsxt/employee/_search?pretty -d '{
"query":
{"multi_match":
{"query":"bin",
"fields":["last_name","first_name"]
}
}
}' -
复合查询
curl -XGET http://localhost:9200/shsxt/employee/_search?pretty -d '{
"query":{
"bool":{
"must" :{"match":{"name":"bin"} },
"must" :{"match":{"age":37} }
}
}
}' -
范围查询
curl -XGET http://localhost:9200/shsxt/employee/_search?pretty -d '{ "query":{ "bool":{ "must" :{"match":{"name":"bin"} }, "must" : {"range": {"age":{ "from":30,"to":40}} } } } }'
DSL配置命令
配置分词规则
index是否建立索引,参数:analyzed(建立索引),no(不建立索引,无法通过该字段进行检索)
analyzer(插入分词)和search_analyzer(检索分词),参数:ik_max_word细粒度,ik_min_word粗粒度,一般插入分词和检索分词使用相同分词粒度以便于检索。
_mappings用于定义字段名称及其数据类型
curl -XPOST http://localhost:9200/ik/ikType/_mapping -d'{ "properties": { "content": { "type": "string", "index":"analyzed", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } }' _mapping 设置相关信息 设置content字段的属性:type(数据类型),index(是否建立索引),analyzer(插入分词),search_analyzer(检索分词)
settings
_settings用于修改索引库默认配置
curl -XPUT '192.168.78.101:9200/shsxt101/_settings' -d '{ "index":{ "number_of_replicas": "2" } }'
插件
head插件
安装
单机安装即可
cd /opt/sxt/elasticsearch-2.4.5/bin/
自动安装: ./plugin install mobz/elasticsearch-head (github网速慢不推荐)
手动安装:将安装包复制到/opt/sxt/elasticsearch-2.4.5/plugins目录下
说明: plugin -h 和plugin install -h 能够得到命令帮助提示
在bin目录下执行:./plugin install file:/opt/sxt/elasticsearch-analysis-ik-1.10.5.zip
注意修改插件的权限:chown -R es:es /opt/sxt/elasticsearch-2.4.5
访问
192.168.163.201:9200/_plugin/head
-
基本查询 使用鼠标直接选择查询
-
复合查询 使用url执行查询
kibana插件
安装
-
在每个es节点上安装license和marvel-agent
-
cd /opt/sxt/elasticsearch-2.4.5/bin
-
本地插件安装
-
./plugin install file:/opt/sxt/marvel-agent-2.4.5.zip
-
./plugin install file:/opt/sxt/license-2.4.5.zip
-
这两个插件能够直接复制到其他节点中
-
cd /opt/sxt/elasticsearch-2.4.5/plugins
scp -r license marvel-agent node2:
pwd
-
-
远程安装
-
./plugin install marvel-agent
-
./plugin install license
-
-
-
安装kibana
-
tar -zxvf kibana-4.6.2-linux-x86_64.tar.gz 将文件移动到/opt/sxt
-
本地安装kibana的marvel 插件
cd /opt/sxt/kibana-4.6.2-linux-x86_64/bin
./kibana plugin --install marvel --url file:///opt/sxt/marvel-2.4.6.tar.gz
-
配置kibana
vim /opt/sxt/kibana-4.6.2-linux-x86_64/config/kibana.yml
elasticsearch.url: "http://node1:9200" 任意配置一个es节点连接
-
-
时间同步
-
启动es集群,并启动kibana
cd /opt/sxt/elasticsearch-2.4.5/bin
./elasticsearch
cd /opt/sxt/kibana-4.6.2-linux-x86_64/bin
./kibana
-
查看监控效果
192.168.163.201:5601(kbana安装在哪个机器选择哪个IP) 选择点击进入Marvel
分词器IK
将ik安装包放到新建ik目录下(mkdir ik) 执行unzip ik.zip
将ik目录移动到es的plugins目录下,并拷贝值其他节点中下
mv ik /opt/sxt/elasticsearch-2.4.5/plugins cd /opt/sxt/elasticsearch-2.4.5/plugins scp -r ik node2:`pwd` scp -r ik node3:`pwd`
在plugins目录下执行chown es:es -R * 修改插件的权限
架构概念
-
索引结构
index索引库,type类型,document文档,field字段。对应关系型数据库的库,表,行,列
document的id唯一标识一个文档数据(若干个字段整体)
-
cluster 集群
-
内部设置主节点选举机制,主节点管理分片与副本,节点发现与删除
-
recovery 有节点加入或退出时,数据恢复,数据重新分布
-
外部可以连接任意节点执行任务(无视主从)
-
-
shaeds 索引分片
-
索引库被拆分为若干分片(默认5片)
-
根据doucment的值,hash计算后取余分配到不同分片中
-
分片数量只能在定义索引库时定义,之后无法修改
curl -XPUT 'localhost:9200/test1/' -d'{"settings":{"number_of_shards":3}}'
-
-
replicas
-
每个分片具备一个主分片,n个副本分片。
-
副本数就是n,可以随时修改
-
副本有助于提高查询效率(向不同节点请求数据),提高数据安全(避免单机故障)。缺点:数据存储量大,存数据时压力大
-
curl -XPUT 'localhost:9200/my_index/' -d'{"settings":{"number_of_replicas":2}}'
-
-
gateway
-
es的数据先存储在内存中,达到阈值后,内存数据持久化到硬盘中
-
为了数据安全设置gateway 相当于日志,用于恢复故障节点的内存
-
磁盘文件的路径:/opt/sxt/elasticsearch-2.4.5/data/
-
-
discovery.zen节点的发现机制:
-
多播:自动发现局域网中es节点,通过9300端口通讯和验证节点
-
单播:关闭自动发现,指定集群各节点的IP
discovery.zen.ping.multicast.enabled 是否允许多波,默认ture
discovery.zen.ping.unicast.hosts 指定集群IP
-
-
Transport
集群内执行tcp协议,外部支持:HTTP,servlet...可以后续插件集成
-
对于需要将数据存储在hdfs上,需要安装插件elasticsearch/elasticsearch-hadoop
重要概念
索引库设计
-
index:字段是否创建索引
analyzed创建
no 不创建(该字段数据不能够执行检索,但获取数据时能够拿到值)一般这样的字段都是:id,序号,url 等不需要被检索的字段
-
分词
analyzer:存储时的分词方式
search_analyzer:检索时的分词方式
一般两个相同,不同的粗细粒度匹配结果不同
-
dynamic参数:true(默认值。动态添加字段),false(忽略新字段)strict(如果碰到陌生字段,抛出异常)
curl -XPOST '192.168.78.101:9200/qiandu' -d '{ "settings":{ "number_of_replicas": "1", "number_of_shards": "3" }, "mappings":{ "web":{ "dynamic":"strict", "properties":{ "title":{"type":"string","index":"analyzed","analyzer": "ik_max_word","search_analyzer": "ik_max_word"}, "content":{"type":"string","index":"analyzed","analyzer": "ik_max_word","search_analyzer": "ik_max_word"}, "url":{"type":"string","index":"no"} } } } }'
关于不存储数据
指定content字段不存储数据 "_source": {"excludes": [ "content"]}
若不存储的字段设置的检索索引,则能够通过检索该字段的数据得到,对应的文档id中其他执行了存储的数据,但该字段的数据时查不到的(单有检索作用)。
进一步的,若存储的数据是其他数据库的id,那么能够建立二级索引
curl -XPOST '192.168.78.101:9200/test3' -d '{ "mappings":{ "web":{ "_source": {"excludes": [ "content"]}, "dynamic":"strict", "properties":{ "title":{"type":"string","index":"no"}, "content":{"type":"string","index":"analyzed","analyzer": "ik_max_word","search_analyzer": "ik_max_word"} } } } }'
es搜索类型
-
query and fetch (最快)(次IO)
向所有分片发送检索请求,各分片返回各自的计算结果数据。
对于指定分页的情况,可能返回数倍于请求的数据
请求前10个数据,每个分片返回前10个计算结果数据,IO压力大
-
query then fetch (默认) (2次IO)
向所有分片发送检索请求,各分片返回各自的计算的结果分数,client排序后选择后,向各分片请求所需的数据
请求前10个数据,每个分片返回各自前10的打分数,client所有接收到的打分数排序,取出前10,再向对应分片请求数据
-
DFS query and fetch(2次IO)
DFS query then fetch(3次IO)
基本同上,前面增加一步:向所有分片发送检索请求,各分片返回各自的检索到的总记录数,client汇总后,将汇中的总数返回各分片,各分片依据返回的总记录数打分处理,后续相同。
分页
– GET xxxx/_search?size=5&from=10
-
from
-
设置检索结果的起始位置的索引,从第几个结果开始显示(0开始)
-
默认0
-
-
size
-
设置检索到的记录数(每页显示几个)
-
默认10
-
分片查询
-
默认随机分片查询randomize across shards
-
优先本地节点查询 _local
-
只查询主分片 _primary
-
优先查询主分片 _primary_first
-
指定节点中查询 _only_node
-
指定分片索引查找 _shards:0,1,2,5
脑裂处理
原因:网络故障,主节点同时执行master与data任务过多
使得主节点只执行监控分配任务,并分配多个备用主节点
-
设置主节点不存储数据
node.master: true
node.data: false
-
设置从节点只执行存储,不参加主节点选举
node.master: false
node.data: true
-
所有节点设置
关闭多波
discovery.zen.ping.multicast.enabled: false
指定及节点的ip/主机名
discovery.zen.ping.unicast.hosts: [“slave1”, “master” , “slave2"]
API(java)
配置代码
用户获取es集群连接,为后续操作提供es连接对象
import org.elasticsearch.common.settings.Settings; //通过集群名,创建客户端连接 Map<String, String> map = new HashMap<String, String>(); map.put("cluster.name", "sxt-es"); client = TransportClient.builder().settings(Settings.builder().put(map)).build(); //设置集群路径,配置至少一个节点地址(ip/主机名),内部连接端口为9300 client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.78.101"), 9300)); client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("node3"), 9300));
索引库操作
主要对象IndicesAdminClient(索引库层面连接)
其3个主要方法
-
prepareCreate() 创建
-
prepareDelete() 删除
-
prepareExists() 判断存在
import org.elasticsearch.client.IndicesAdminClient; //获取索引库层面连接 IndicesAdminClient indices = client.admin(). indices(); //执行索引库存在判断,其中prepareExists可传入可变参数,执行索引查询 IndicesExistsResponse actionGet = indices.prepareExists("test").execute().actionGet(); if (actionGet.isExists()) {System.out.print("test索引库已存在");} //索引库删除操作,可以进一步获取响应数据 indices.prepareDelete("test").execute(); //使用map设置创建数据库的参数,分片数和备份数 Map<String, String> setMap = new HashMap<>(); setMap.put("number_of_replicas", "0"); setMap.put("number_of_shards", "3"); //执行索引库创建,设置索引库名与参数 indices.prepareCreate("test").setSettings(setMap).execute();
索引操作
-
创建索引(数据插入)
//通过map准备数据,存入字段名与字段值 Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "binbin"); map.put("age", 30); //设置文档id方式(索引库为test,type为ttt,文档id为80) IndexResponse r1 = client.prepareIndex("test","ttt","80").setSource(hashMap).execute().actionGet(); //自动创建文档id方式 IndexResponse r2 = client.prepareIndex("test","ttt").setSource(hashMap).execute().actionGet(); //获取文档id String id1=r1.getId(); String id2=r2.getId();
//另一种插入对象 IndexRequest indexRequest = new IndexRequest("test", "tweet", "333").source( XContentFactory.jsonBuilder() .startObject() .field("user", "kimchy") .field("postDate", new Date()) .field("message", "trying out Elasticsearch") .endObject());
-
直接获取数据
通过document的id直接获取数据
import org.elasticsearch.action.get.GetResponse; //执行数据获取 GetResponse response =client.prepareGet("test","ttt","70").execute().actionGet(); //从结果中获取数据 long version=response.getVersion();//获取数据版本 //获取数据字段,并遍历map Map<String, Object> source = response.getSource(); for (String key : source.keySet()){System.out.print(key + "+" + source.get(key));}
-
检索索引
索引库查询对象:SearchRequestBuilder。通过该对象设置检索参数
//获取索引库查询对象,参数为可变参数,可传入多个索引库 SearchRequestBuilder builder = client.prepareSearch("test"); //设置检索的type,可变参数可传入多个 builder.setTypes("ttt"); //设置分页 builder.setFrom(0);//设置设置检索结果的起始位置,从0开始(从第几个结果开始显示) builder.setSize(5);//设置检索到的记录数(每页显示几个) //设置结果排序,根据指定字段的值排序及排序顺序 //若不设置则默认按照TF-IDF打分并排序;若自定义排序则不再打分 builder.addSort("age",SortOrder.DESC); //设置具体检索内容builder.setQuery(),通过通过QueryBuilders对象的方法构建不同的查询 //关键词查询 String key="ccc";//自定义的关键词 //设置关键词和执行查找的字段(在name字段中查找匹配ccc的结果) builder.setQuery(QueryBuilders.multiMatchQuery(key,"name")); //设置范围查询(匹配15-20之间的结果) builder.setQuery(QueryBuilders.rangeQuery("age").from(15).to(20)); //执行查询,获取结果对象 SearchResponse searchResponse=builder.get();
解析SearchResponse对象的查询结果数据
//解析返回对象,获取命中结果 SearchHits hits = searchResponse.getHits(); //解析命中条数(long) hits.getTotalHits() //将命中结果解析为数组对象,元素为单条命中元素 SearchHit[] array_hits = hits.getHits(); //遍历数组,解析命中的每条元素 for(SearchHit hit:array_hits){ hit.getScore();//获取打分结果 hit.getId();//获取document的id hit.index();//获取结果的需要 //解析document中的每个字段 Map<String, Object> source = hit.getSource(); for(String s: source.keySet()){ //遍历得到key,再获取值 System.out.println(s); System.out.println(source.get(s)); } }
-
更新索引
UpdateRequest对象构建更新,以下均为局部更新
-
单更新
-
结构1
import org.elasticsearch.action.update.UpdateRequest; //获取更新对象 UpdateRequest ur=new UpdateRequest(); //设置参数 ur.index("text");//索引库 ur.type("ttt");//索引type ur.id("80");//document的id //存入字段 Map<String, Object> map = new HashMap<>(); map.put("age", "25"); map.put("date", "2018-01-01"); ur.doc(map); //执行插入 client.update(ur);
-
结构2(不同的字段设置格式)
UpdateRequest ur=new UpdateRequest(); ur.index("text"); ur.type("ttt"); ur.id("80"); updateRequest.doc( XContentFactory.jsonBuilder() .startObject() .field("age", "26") .field("city", "shanghai") .endObject()); client.update(ur);
-
更新插入(若id没有则插入,有则更新字段,局部更新)
//数据准备 Map<String, Object> map = new HashMap<>(); map.put("name", "lyp"); map.put("age", "25"); //插入对象 IndexRequest indexRequest = new IndexRequest("test", "employee", "70").source(map); //更新对象 UpdateRequest updateRequest = new UpdateRequest("test", "employee", "70").doc(map); //将插入对象放在更新对象中 updateRequest.upsert(indexRequest); //执行 client.update(updateRequest);
-
-
删除索引
//根据document的id值,删除数据 DeleteResponse response = client.prepareDelete("test", "employee", "80").execute().actionGet(); System.out.print(response.isFound());
-
批量操作,能够批量执行不同的操作
BulkRequestBuilder批处理对象,一次性执行
import org.elasticsearch.action.bulk.BulkRequestBuilder; BulkRequestBuilder br = new BulkRequestBuilder(); //插入操作对象 IndexRequest ir= new IndexRequest("test","tweet","333").source(XContentFactory.jsonBuilder().startObject().field("user", "kimchy").field("postDate", new Date()).endObject()); //删除操作对象 DeleteResponse dr = client.prepareDelete("test", "aaa", "80"); //将操作对象置入批处理对象中 br.add(ir); br.add(dr); //执行批处理,返回批处理结果对象 BulkResponse bulkResponse = bulkRequest.get(); //判断结果是否存在,失败 boolean hasfail=bulkResponse.hasFailures();
测试数据爬取
使用liunx的wget命令执行爬虫,具体如下
wget -o /tmp/wget.log -P /root/data --no-parent --no-verbose -m -D www.shsxt.com -N --convert-links --random-wait -A html,HTML,shtml,SHTML http://www.shsxt.com # 日志位置:/tmp/wget.log ,数据存放位置:/root/data # 爬虫爬取范围: -D www.shsxt.com # 爬取文件类型: -A html,HTML,shtml,SHTML # 爬取起始页面: 最后一个 http://www.shsxt.com
py的爬虫框架Scrapy,java的爬虫框架Nutch,c语言的爬虫框架wget
网页解析
-
使用第三方jar包jericho-html-3.3.jar解析网页。
-
使用net.htmlparser.jericho.Source类,对爬取到的html进行数据清洗(ETL),得到第一个title(网页标题)和文本数据。再根据html所在目录和指定的域名获取url
import net.htmlparser.jericho.Source; //file就是html文件的Flie对象 Source source = new Source(file); //解析第一个title标签中的文本 String title = source.getFirstElement("title").getTextExtractor().toString(); //解析html文件中的 String content = source.getTextExtractor().toString(); //获取url:在文件系统中的路径为D:data\www.shsxt.com\2017\recoll\676.html。截取到的url为www.shsxt.com\2017\recoll\676.html int index = file.getAbsolutePath().indexOf("www.shsxt.com"); String url = file.getAbsolutePath().substring(index);
//递归获取指定路径的文件对象,包括子文件. import org.apache.commons.io.FileUtils; public static final String FILE_PATH = "G:\\teach\\doc\\elasticsearch\\data"; Collection<File> files = FileUtils.listFiles(new File(FILE_PATH), TrueFileFilter.INSTANCE,TrueFileFilter.INSTANCE);
es检索高亮
es支持高亮检索
//设置查询指定索引库与type SearchRequestBuilder builder = getClient().prepareSearch("test"); builder.setTypes("ttt"); // 设置高亮字段名称 builder.addHighlightedField("title"); builder.addHighlightedField("content"); //设置每个结果最多显示3个碎片段,每个碎片段之间用...隔开 //片段就是包含高亮关键字的一小段文本,从总文本中截取而来 builder.setHighlighterNumOfFragments(3); // 设置高亮前缀 builder.setHighlighterPreTags("<font color='red' >"); // 设置高亮后缀 builder.setHighlighterPostTags("</font>"); //执行查找,设置查找的信息域,从title和content里找 builder.setQuery(QueryBuilders.multiMatchQuery(key, "title", "content")); //结果解析 SearchResponse searchResponse = builder.get(); SearchHits hits = searchResponse.getHits(); SearchHit[] hits2 = hits.getHits(); for (SearchHit hit : hits2) { //源数据,不包含高亮(aaabbbccc);结果数据,含高亮( aaa<font color='red' >bbb</font>ccc ) if(hit.getHighlightFields().get("title")==null){ //title中没有包含关键字,打印原先的title System.out.print(hit.getSource().get("title").toString()); }else{ //打印第一个具备高亮的title HighlightField titleField = hit.getHighlightFields().get("title"); Text[] fragments = titleField.getFragments(); String highlightTitle= fragments[0].toString(); System.out.print(highlightTitle); } if(hit.getHighlightFields().get("content")==null){ //content中没有包含关键字,答应原有数据 System.out.print(hit.getSource().get("content").toString()); }else{ //打印具备高亮的碎片段 StringBuilder sb =new StringBuilder(); for(Text text: hit.getHighlightFields().get("content").getFragments()){ sb.append(text.toString()+"..."); } System.out.print(sb.toString()); } } page.setList(list);
优化
-
分片数量
分片多,检索时打开文件多;分片少,单片数据检索任务大
优化:分片最多存储约20G
-
副本数量
建议2-3个
可以提高检索效率(提高使用空闲节点的可能,单节点降低访问压力)与数据安全(备份多)
服务器造成额外的存储压力和数据同步压力
-
大量数据存入优化
存入数据时副本数设为0,存好后修改副本数。降低数据存储时的压力
-
调大系统的"最大打开文件数",建议32K甚至是64K
– ulimit -a (查看)
– ulimit -n 32000(设置)
-
JVM调优,修改bin/elasticsearch.in.sh中ES_MIN_MEM和ES_MAX_MEM
建议设置一样大,避免频繁的分配内存。一般设置总内存的60%
-
锁定物理内存地址,避免内存swapped
修改文件conf/elasticsearch.yml
bootstrap.mlockall: true
-
segment优化
-
手动清理删除数据
方式1:curl -XPOST 'http://localhost:9200/elasticsearch/_optimize?only_expunge_deletes=true'
方式2:client.admin().indices().prepareOptimize("elasticsearch").setOnlyExpungeDeletes(true).get();
-
all域
索引库中会额外存一个all的字段,存储一个document的中一个或者多个域(字段)的内容,检索时直接从all域中取全部数据,提高查询效率,但加大了存储与CPU压力
禁用命令: "_all" : {"enabled":false}
es配合HBase
es作为hbase的二级索引,es索引库同步存储hbase的rowkey和部分需要检索的字段。
解决hbase的rowkey查询不灵活的问题
-
数据存储hbase时,将rowkey与数据存入es
-
es对数据建立索引,但不执行存储数据;es存储rowkey,但不建立rowkey的索引
-
通过es对数据的检索得到rowkey,进而对从hbase中根据rowkey获取数据
-