ElasticSearch已经配置好ik分词和mmseg分词(转)
ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。支持通过HTTP使用JSON进行数据索引。
官方站点:http://www.elasticsearch.com/
中文站点:http://es-cn.medcl.net/
1.安装
必须先安装Java环境,并设置 JAVA_HOME => C:\Program Files\Java\jdk1.6.0_18
elasticsearch-rtf 中文入门集成包 https://github.com/medcl/elasticsearch-rtf
使用git签出,下载到本地。windows下,执行bin下面的elasticsearch.bat。linux下,执行bin下面或者service下面elasticsearch。
2.角色关系对照
elasticsearch 跟 MySQL 中定义资料格式的角色关系对照表如下
MySQL elasticsearch
database index
table type
table schema mapping
row document
field field
选用原因
主要原因有:实时性能优越;安装配置简单;RESTful API 和 JSON 格式的文档型数据,降低开发调试的难度。 另外,Tire 这个 Gem 可以简单方便的与 ActiveRecord 整合。 测试中发现:ES 自带了中文分词,支持中文搜索,但是,可以换用更高效精确的分词插件。
业界资讯:GitHub searches 20TB of data using Elasticsearch, including 1.3 billion files and 130 billion lines of code.
简单介绍
ElasticSearch 是开源搜索平台领域的一个新成员。 ElasticSearch(简称 ES) 是一个基于 Lucene 构建的开源,分布式,RESTful 搜索引擎。 设计用于云计算中,能够达到搜索实时、稳定、可靠和快速,并且安装使用方便。 支持通过 HTTP 请求,使用 JSON 进行数据索引。
特点优势
(1)Open Source(开源)
(2)Apache Lucene(基于 Lucene)
(3)Schema Free(模式自由)
(4)Document Oriented(面向文档型的设计)
(5)Real Time Data & Analytics(实时索引数据)
(6)Distributed(分布式)
(7)High Availability(高可靠性)
(8)其他特性:RESTful API;JSON format;multi-tenancy;full text search;conflict management;per-operation persistence
================================================
分布式搜索elasticsearch 中文分词集成
对于索引可能最关系的就是分词了 一般对于es 来说默认的smartcn 但效果不是很好
一个是ik的,一个是mmseg的,下面分别介绍下两者的用法,其实都差不多的,先安装插件,命令行:
下载ik相关配置词典文件到config目录:
cd config
wget http://github.com/downloads/medcl/elasticsearch-analysis-ik/ik.zip --no-check-certificate
unzip ik.zip
rm ik.zip
分词配置
ik分词配置,在elasticsearch.yml文件中加上
index:
analysis:
analyzer:
ik:
alias: [ik_analyzer]
type: org.elasticsearch.index.analysis.IkAnalyzerProvider
或
index.analysis.analyzer.ik.type : “ik”
安装mmseg插件:
bin/plugin -install medcl/elasticsearch-analysis-mmseg/1.1.0
下载相关配置词典文件到config目录
cd config
wget http://github.com/downloads/medcl/elasticsearch-analysis-mmseg/mmseg.zip --no-check-certificate
unzip mmseg.zip
rm mmseg.zip
mmseg分词配置,也是在在elasticsearch.yml文件中
index:
analysis:
analyzer:
mmseg:
alias: [news_analyzer, mmseg_analyzer]
type: org.elasticsearch.index.analysis.MMsegAnalyzerProvider
mmseg分词还有些更加个性化的参数设置如下
index:
analysis:
tokenizer:
mmseg_maxword:
type: mmseg
seg_type: "max_word"
mmseg_complex:
type: mmseg
seg_type: "complex"
mmseg_simple:
type: mmseg
seg_type: "simple"
这样配置完后插件安装完成,启动es就会加载插件。
定义mapping
在添加索引的mapping时就可以这样定义分词器
{
"page":{
"properties":{
"title":{
"type":"string",
"indexAnalyzer":"ik",
"searchAnalyzer":"ik"
},
"content":{
"type":"string",
"indexAnalyzer":"ik",
"searchAnalyzer":"ik"
}
}
}
}
indexAnalyzer为索引时使用的分词器,searchAnalyzer为搜索时使用的分词器。
java mapping代码如下:
XContentBuilder content = XContentFactory.jsonBuilder().startObject()
.startObject("page")
.startObject("properties")
.startObject("title")
.field("type", "string")
.field("indexAnalyzer", "ik")
.field("searchAnalyzer", "ik")
.endObject()
.startObject("code")
.field("type", "string")
.field("indexAnalyzer", "ik")
.field("searchAnalyzer", "ik")
.endObject()
.endObject()
.endObject()
.endObject()
测试分词可用调用下面api,注意indexname为索引名,随便指定一个索引就行了
http://localhost:9200/indexname/_analyze?analyzer=ik&text=测试elasticsearch分词器
附:
ik分词插件项目地址:https://github.com/medcl/elasticsearch-analysis-ik
mmseg分词插件项目地址:https://github.com/medcl/elasticsearch-analysis-mmseg
配置好的es版本,地址如下:https://github.com/medcl/elasticsearch-rtf
================================================
cluster
代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。
shards
代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
replicas
代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当个某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
recovery
代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
river
代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的。
gateway
代表es索引快照的存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到本地硬盘。gateway对索引快照进行存储,当这个es集群关闭再重新启动时就会从gateway中读取索引备份数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的s3云存储服务。
discovery.zen
代表es的自动发现节点机制,es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。
Transport
代表es内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。
------------------------------------------------
云计算平台(检索篇)-Elasticsearch-配置篇
ElasticSearch安装好后我们需要对ElasticSearch的Config进行一系列配置,具体如下:
cluster.name: rmscloud
集群名称
node.name: "rcnode21"
节点名称
node.tag: "tag21"
节点标签
node.data: true
节点是否存储数据
index.number_of_shards: 5
索引分片数
index.number_of_replicas: 1
索引副本数
path.data: /data/elasticsearch/data
数据目录存放位置
path.logs: /data/elasticsearch/log
日志数据存放位置
bootstrap.mlockall: true
内存
index.cache.field.max_size: 500000
索引缓存
index.cache.field.expire: 5m
索引缓引过期时间
其它配置基本上不用调,具体可参考附录。另外需要的调配置是分词具体例子如下:
index:
analysis:
tokenizer:
my_pinyin:
type: pinyin
first_letter: "prefix"
padding_char: ""
pinyin_first_letter:
type: pinyin
first_letter: "only"
mmseg_maxword:
type: mmseg
seg_type: "max_word"
mmseg_complex:
type: mmseg
seg_type: "complex"
mmseg_simple:
type: mmseg
seg_type: "simple"
semicolon_spliter:
type: pattern
pattern: ";"
pct_spliter:
type: "pattern"
pattern: "[%]+"
filter:
ngram_min_2:
max_gram: 10
min_gram: 2
type: nGram
ngram_min_1:
max_gram: 10
min_gram: 1
type: nGram
min2_length:
min: 2
max: 4
type: length
analyzer:
lowercase_keyword:
type: custom
filter: [standard,lowercase]
tokenizer: standard
lowercase_keyword_ngram_min_size1:
type: custom
filter: [ngram_min_1,standard,lowercase]
tokenizer: nGram
lowercase_keyword_ngram_min_size2:
type: custom
filter: [ngram_min_2,standard,lowercase,min2_length,stop]
tokenizer: nGram
lowercase_keyword_ngram:
type: custom
filter: [ngram_min_1,standard,lowercase]
tokenizer: nGram
lowercase_keyword_without_standard:
type: custom
filter: [lowercase]
tokenizer: keyword
lowercase_whitespace:
type: custom
filter: [lowercase]
tokenizer: whitespace
ik:
alias: [ik_analyzer]
type: org.elasticsearch.index.analysis.IkAnalyzerProvider
ike:
alias: [ike_analyzer]
type: org.elastichsearch.ik.index.IkAnalyzerProvider
usermode: true
mmseg:
alias: [mmseg_analyzer]
type: org.elasticsearch.index.analysis.MMsegAnalyzerProvider
comma_spliter:
type: "pattern"
pattern: "[,|\\s]+"
pct_spliter:
type: "pattern"
pattern: "[%]+"
custom_snowball_analyzer:
type: "snowball"
language: "English"
simple_english_analyzer:
type: "custome"
tokenizer: whitespace
filter: [standard,lowercase,snowball]
edge_ngram:
type: custom
tokenizer: edgeNGram
filter: [lowercase]
pinyin_ngram_analyzer:
type: custom
tokenizer: my_pinyin
filter: [standard,lowercase,nGram]
pinyin_first_letter_analyzer:
type: custom
tokenizer: pinyin_first_letter
filter: [standard,lowercase]
custom_auth_en_analyzer:
type: custom
tokenizer: semicolon_spliter
filter: [standard,snowball,lowercase,trim]
index.analysis.analyzer.default.type : "keyword"
进行完Config的配置后还需要对bin目录下面的elastichsearch进行配置,此处主要是控制JVM的一些参数
ES_MIN_MEM=27G
ES_MAX_MEM=27G
调整JVM的最大内存和最小内存就可以了,其它JVM参数见附录。
------------------------------------------------
云计算平台(检索篇)-Elasticsearch-Linux优化篇
Elasticsearch在Linux系统环境中运行,需要对Linux系统进行一系列调优,这样可以提高ElasticSearch的检索效率。主要的需要调优的参数如下:
1. Linux调整文件数
/etc/security/limits.conf
在文件中增加
* soft nofile 8192
* hard nofile 20480
* - memlock unlimited
在登陆中添加下面命令行
/etc/pam.d/login
session required /lib64/security/pam_limits.so(在不同系统中文件位置不同)
2. 关闭文件的更新时间
/etc/fstab
在文件中添加一行
/dev/sda7 /data/elasticsearch ext4 noatime,nodiratime 0 0
(此处的/dev/sda7 可以通过df –h查看目录所在分区)
3. 修改防火墙设置
为方便调适暂时关闭
/etc/init.d/iptables stop
------------------------------------------------
云计算平台(检索篇)-Elasticsearch-索引篇
Es索引的我们可以理解为数据入库的一个过程。我们知道Es是基于Lucene框架的一个分布式检索平台。索引的同样也是基于Lucene创建的,只不过在其上层做了一些封闭。
Es的索引过程比较通用的大体上有两种方式,其一是得用自身Rvier从数据库中拉数据,当然现在已经有了很多相关插件,Mysql、MDB等数据库。这种方式可以做到近时实索引,因为River是定时从数据库拉数据与索引数据进行比对。这种方式经较适合数据有周期的更新。
下面以Mysql-River plugins为例:
1、 安装Mysql-River 插件
bin/plugin -install /path/to/plugin/river-mysql.zip
2、 当安装好Mysql-River plugin 后,一般可以马上使用,但建立重新加载Es集群。查看log中是否正确的加载了Mysql-River Plugin(在后面我们讲到如何开发相关Plugin)。
3、 配置Es索引与Mysql 数据之间的对应关系。
建立索引(相关Mapping 信息如下:)
curl -XPUT 127.0.0.1:9200/elasticsearchindexname/elasticsearchtypename/_mapping -d
"elasticsearchtypename" : {
"_timestamp":{
"enabled":true
}
}
将River索引的配置也提交到Es集群中:
curl -XPUT 127.0.0.1:9200/_river/river-mysql/_meta –d
{
"type":"mysql",
"mysql":{
"index":"elasticsearchindexname",(索引名称)
"type":"elasticsearchtypename",(类型)
"hostname":"127.0.0.1:3306",(服务器)
"database":"ESDATA",(数据库名称)
"username":"root",(用户名)
"password":"",(密码)
"uniqueIdField":"_ID",(标识)
"query":"select RID,PNAME FROM wf_mds_chn_biaozhun",(SQL语句)
"deleteOldEntries":"false",
"interval":"60000"(更新周期)
}
}
同时你会在Es看到你的索引中开始导数据了,当然些时也会出现一个对应的保存配置的索引,现在很多River都只能索引字段与数据库的字段一一对应。如果需要个性化定制,可以到Github上下载相关代码进行修改。我们可以看到只要继续River(接口)和AbstractRiverComponent(类)便可以进行相关开发了。
public class MysqlRiver extends AbstractRiverComponent implements River
另外一种索引方式当然就是我们把数据Put到Es中去了,最简单的我们可以用下面命令就完成:
$ curl -XPUT 'http://localhost:9200/twitter/tweet/1' -d '{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elastic Search"
}'
对上面的命令解释一下:
Twitter:索引名称
Tweet:类型名称
1:ID值
具体我会在下篇中讲解索引名称和类型的关系,当然-d 后面的就是值了。这是单条Put数据的方式虽然简单,但是如果说数据量很大的情况下还是不建议用这种方式,可以改用批量导入的方式也就是传说中的Bluk了,Bluk原量很简单,我们把数据放到缓存中,一次Put多条数据到Es集群中去,Bluk当然要用代码实现了,给出一个例子如下:
public static void Index() throws ElasticSearchException, IOException, NumberFormatException, SQLException {
// TODO Auto-generated method stub
// Node node = nodeBuilder().client(true).node();
Settings settings = ImmutableSettings.settingsBuilder()
.put("cluster.name", "elasticsearch_wf").build();
Client client = new TransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(
"168.160.200.250", 9300));
////������е��ܼ�¼��ֳ�5000��һ�����ѯ
int countRe=100000000; //MySqlClass.getCount("select count(*) from test");
if(countRe>0)
{
int readercount=1;
if(countRe>5000)
{
readercount=countRe%5000==0?countRe/5000:countRe/5000+1;
}
////ÿ�ζ�ȡ5000���¼
for(int j=0;j<readercount;j++)
{
ResultSet rs = MySqlClass.executeQuery("select * from test");
BulkRequestBuilder bulkRequest = client.prepareBulk();
try {
if (rs != null) {
int i = 1;
while (rs.next()) {
bulkRequest.add(client.prepareIndex("qtest", String.valueOf(i++)).setSource(
jsonBuilder().startObject()
.field("id", rs.getInt("id"))
.field("�й�", rs.getString("title"))
.field("AB_EN", rs.getString("descript"))
.field("AF_CN",rs.getString("text"))
.endObject()));
}
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
if (bulkResponse.hasFailures()) {
/* has Failures handler Error */
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
client.close();
}
上面只是一个简单的例子,大量可以考虑用从线程方式,另外Client链接数其实还是比较占资源的,大家可以考虑将出封闭到一个链接池中,提供效率。
整个建索引的过程Es在Lucene的基础上还是做了很多的优化,但主体上我们对应到Lucene里面基实就是如下代码:
public class Index {
private IndexWriter writer = null;
private static Analyzer ANALYZER = new IKAnalyzer();
private String FilePath = null;
public Index(String FilePath, String IndexPath) {
try {
IndexWriterConfig writerConfig = new IndexWriterConfig(
Version.LUCENE_36, ANALYZER);
this.writer = new IndexWriter(
FSDirectory.open(new File(IndexPath)), writerConfig);
this.FilePath = FilePath;
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Init Create Index
*/
public void Init() {
try {
if (FilePath.length() > 0) {
// 读目录中txt文件
File file = new File(FilePath);
List<File> files = new ArrayList<File>();
this.ListAllFile(file, files);
// //将File转换为 Document对象
for (File sfs : files) {
this.writer.addDocument(this.getDocument(sfs));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Close Index
*/
public void Close() {
try {
this.writer.commit();
this.writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 获取所有txt文件
*/
private List<File> ListAllFile(File fileOrDir, List<File> files)
throws Exception {
if (fileOrDir != null && files != null) {
if (fileOrDir.isDirectory()) {
File[] fs = fileOrDir.listFiles();
for (File sfs : fs) {
if (sfs.isDirectory())
this.ListAllFile(sfs, files);
else files.add(sfs);
}
} else {
files.add(fileOrDir);
}
}
return null;
}
/*
* Get Document
*/
private Document getDocument(File f) throws Exception {
Document doc = new Document();
FileInputStream is = new FileInputStream(f);
byte[] buf = new byte[is.available()];
is.read(buf);
String contentStr = new String(buf,"GBK");
Field content = new Field("content", contentStr, Field.Store.YES,
Field.Index.ANALYZED);
doc.add(content);
Field path = new Field("path", f.getAbsolutePath(), Field.Store.YES,
Field.Index.ANALYZED);
Field size=new Field("size",String.valueOf(f.getTotalSpace()),Field.Store.YES,Field.Index.NOT_ANALYZED);
doc.add(size);
Random rm=new Random();
int year=rm.nextInt(20);
Field time=new Field("time",String.valueOf(1990+year),Field.Store.YES,Field.Index.NOT_ANALYZED);
doc.add(time);
doc.add(path);
is.close();
return doc;
}
}
------------------------------------------------
云计算平台(检索篇)-Elasticsearch-Mapping篇
Es Mapping篇主要是讲解Mapping的一些相关配置与需要注意的地方,说到Mapping大家可能觉得有些不解,其实我大体上可以将Es 理解为一个数据管理平台,那么index 当然就是库了,type可以理解为表,mapping可以理解为表的结构和相关设置的信息(当然mapping有更大范围的意思)。Mapping的作用域也是从cluster、node、index、type。
curl -XPOST localhost:9200/wf_mds_org(索引名称) -d '{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"index.refresh_interval": "-1",
"index.translog.flush_threshold_ops": "100000"
},
"mappings": {
"org": { //(类型)
"_all": {
"analyzer": "ike"
},
"_source": {
"compress": true
},
"properties": {
"_ID": {
"type": "string",
"include_in_all": true,
"analyzer": "keyword"
},
"NAME": {
"type": "multi_field",
"fields": {
"NAME": {
"type": "string",
"analyzer": "keyword"
},
"IKO": {
"type": "string",
"analyzer": "ike"
}
}
},
"SHORTNAME": {
"type": "string",
"index_analyzer": "pct_spliter",
"search_analyzer": "keyword",
"store": "no"
},
"OLDNAME": {
"type": "multi_field",
"fields": {
"OLDNAME": {
"type": "string",
"analyzer": "keyword"
},
"IKO": {
"type": "string",
"analyzer": "ike"
}
}
},
"TNAME": {
"type": "string",
"analyzer":"custom_snowball_analyzer",
"store": "no"
},
"TSNAME": {
"type": "string",
"index": "no",
"store": "no"
},
"TONAME": {
"type": "string",
"index": "no",
"store": "no"
}
}
}
}
}'
上面给出了一个完整Mapping,我们可将Mapping信息大致分成settings和mappings两个部分,settings主要是作用于index的一些相关配置信息,如分片数、副本数等(分片和副本在es简介中讲过,更加详细的东西会在索引优化篇中讲)、tranlog同步条件、refresh条条等。Mappings部分主是要结果构的一些说明,mappings 我们可以看到主体上大致又分成_all、_source、properites这三个部分。
1、_all:主要指的是All Field字段,我们可以将一个或都多个包含进不,在进行检索时无需指定字段的情况下检索多个字段。前提是你得开启All Field字段
"_all" : {"enabled" : true}
2、_source:主要指的是Source Field字段Source可以理解为Es除了将数据保存在索引文件中,另外还有一分源数据。_source字段我在们进行检索时相当重要,如果在{"enabled" : false}情况下默认检索只会返回ID,你需通过Fields字段去倒索索引中去取数据,当然效率不是很高。如果觉得enabale:true时,索引的膨涨率比较大的情况下可以通过下面一些辅助设置进行优化:
Compress:是否进行压缩,建议一般情况下将其设为true
"includes" : ["author", "name"],
"excludes" : ["sex"]
上面的includes和 excludes主要是针对默认情况下面_source一般是保存全部Bulk过去的数据,我们可以通过include,excludes在字段级别上做出一些限索。
3、properites部分是最重要的部分主要是针对索引结构和字段级别上面的一些设置
"NAME": { //字段项名称对应lucene里面FiledName
"type": "string",//type为字段项类型
"analyzer": "keyword"//字段项分词的设置对应Lucene里面的Analyzer
},
在Es中字段项的 type是一个很重要的概念,在Es中在Lucene的基础上提供了比较多的类型,而这些类型对应这一些相关的检索特性如 Date型 我可以使用 [2001 TO 2012]的方式进行范围检索等,Es 的类型有如下一些:
简单类型:
String:字符型最常用的
Integer:整型
Long:长整型
Float:浮点型
Double:双字节型
Boolean:布尔型
复杂类型:
Array:数组型
“lists”:{{“name”:”…”},{“name”:”…”}}
Object:对象类型
“author”:{“type”:”object”,”perperites”:{“name”:{“type”:”string”}}}
说到Array和Object有一个性能上的问题,Es中提供了Facet检索,据Es的作者提供的消息,在做Facet时object类型相比与array的内存要占用的少,但我本人经过测试效果不是很明显有兴趣的可以测试一下。
Multi_field:多分词字段,针对一个字段提供多种分词方式
Nested: 嵌入类型用的还是比较多的
类型常用的也就这些了,还有一些类型大家可以参考官网,另外一个比较重的方面的就是分词了(analyzer),不管在目前任何检索系统是分词决定这检索的查全与查准及索引的膨涨率等。在Es中analyzer的作用域也是从cluster、index、filed这三个作用域。Cluster的配置在配置中讲过,下面以Field为主(另外具体的分词一些相关东西会在分词篇中讲)
Analyzer,在Lucene中是一个分词器的概念,我们知道Es是建立在Lucene之上的,所以这里的Analzyer同样的也适用,Mapping 中的Analyzer主在是指定字段采用什么分词器,具体的程序和配置分词在插件和配置都有过一些说明。
Analyzer在Es中分为index_analyzer和search_analyzer
Index_analzyer:指的是索引过程中采用的分词器
Search_analyzer:指的是检索过程中采用的分词器
我们知道index和search是两个过程,但是尽量保证这两个过程和分词方式一致这样可以保证查全和查准,否则再牛B的分词,index和search采用的不相同也是无用功。
与analyzer与之相关的就是别外一项index项
"HC":{ "type":"string", "index":"no", "store":"no"}
Index表示该字段是否索引,如果index为no那个analyzer设为啥也没用。
最后是”store”项了store项表示该项是否存储到倒索索引中去,并不是_source,当项mapping中还有很多可以设置和优化的地方,会面在慢慢讨论。在mapping中index和store如果大家有时候觉得有点和source搞不清楚,大家可以参考lucene中的Field.Store.YES,Field.Index.NOT_ANALYZED,Field.Index等相关设置就比较明白了。
-----------------------------------------------
云计算平台(检索篇)-Elasticsearch-索引优化篇
ES索引优化篇主要从两个方面解决问题,一是索引数据过程;二是检索过程。
索引数据过程我在上面几篇文章中有提到怎么创建索引和导入数据,但是大家可能会遇到索引数据比较慢的过程。其实明白索引的原理就可以有针对性的进行优化。ES索引的过程到相对Lucene的索引过程多了分布式数据的扩展,而这ES主要是用tranlog进行各节点之间的数据平衡。所以从上我可以通过索引的settings进行第一优化:
"index.translog.flush_threshold_ops": "100000"
"index.refresh_interval": "-1",
这两个参数第一是到tranlog数据达到多少条进行平衡,默认为5000,而这个过程相对而言是比较浪费时间和资源的。所以我们可以将这个值调大一些还是设为-1关闭,进而手动进行tranlog平衡。第二参数是刷新频率,默认为120s是指索引在生命周期内定时刷新,一但有数据进来能refresh像lucene里面commit,我们知道当数据addDoucment会,还不能检索到要commit之后才能行数据的检索所以可以将其关闭,在最初索引完后手动refresh一之,然后将索引setting里面的index.refresh_interval参数按需求进行修改,从而可以提高索引过程效率。
另外的知道ES索引过程中如果有副本存在,数据也会马上同步到副本中去。我个人建议在索引过程中将副本数设为0,待索引完成后将副本数按需量改回来,这样也可以提高索引效率。
"number_of_replicas": 0
上面聊了一次索引过程的优化之后,我们再来聊一下检索速度比较慢的问题,其实检索速度快度与索引质量有很大的关系。而索引质量的好坏与很多因素有关。
一、分片数
分片数,与检索速度非常相关的的指标,如果分片数过少或过多都会导致检索比较慢。分片数过多会导致检索时打开比较多的文件别外也会导致多台服务器之间通讯。而分片数过少为导至单个分片索引过大,所以检索速度慢。
在确定分片数之前需要进行单服务单索引单分片的测试。比如我之前在IBM-3650的机器上,创建一个索引,该索引只有一个分片,分别在不同数据量的情况下进行检索速度测试。最后测出单个分片的内容为20G。
所以索引分片数=数据总量/单分片数
目前,我们数据量为4亿多条,索引大小为近1.5T左右。因为是文档数据所以单数据都中8K以前。现在检索速度保证在100ms 以下。特别情况在500ms以下,做200,400,800,1000,1000+用户长时间并发测试时最坏在750ms以下.
二、副本数
副本数与索引的稳定性有比较大的关系,怎么说,如果ES在非正常挂了,经常会导致分片丢失,为了保证这些数据的完整性,可以通过副本来解决这个问题。建议在建完索引后在执行Optimize后,马上将副本数调整过来。
大家经常有一个误去副本越多,检索越快,这是不对的,副本对于检索速度其它是减无增的我曾做过实现,随副本数的增加检索速度会有微量的下降,所以大家在设置副本数时,需要找一个平衡值。另外设置副本后,大家有可能会出现两次相同检索,出现出现不同值的情况,这里可能是由于tranlog没有平衡、或是分片路由的问题,可以通过?preference=_primary 让检索在主片分上进行。
三、分词
其实分词对于索引的影响可大可小,看自己把握。大家越许认为词库的越多,分词效果越好,索引质量越好,其实不然。分词有很多算法,大部分基于词表进行分词。也就是说词表的大小决定索引大小。所以分词与索引膨涨率有直接链接。词表不应很多,而对文档相关特征性较强的即可。比如论文的数据进行建索引,分词的词表与论文的特征越相似,词表数量越小,在保证查全查准的情况下,索引的大小可以减少很多。索引大小减少了,那么检索速度也就提高了。
四、索引段
索引段即lucene中的segments概念,我们知道ES索引过程中会refresh和tranlog也就是说我们在索引过程中segments number不至一个。而segments number与检索是有直接联系的,segments number越多检索越慢,而将segments numbers 有可能的情况下保证为1这将可以提到将近一半的检索速度。
$ curl -XPOST 'http://localhost:9200/twitter/_optimize? max_num_segments =1'
五、删除文档
删除文档在Lucene中删除文档,数据不会马上进行硬盘上除去,而进在lucene索引中产生一个.del的文件,而在检索过程中这部分数据也会参与检索,lucene在检索过程会判断是否删除了,如果删除了在过滤掉。这样也会降低检索效率。所以可以执行清除删除文档。
$ curl -XPOST 'http://localhost:9200/twitter/_optimize? only_expunge_deletes =true'
-----------------------------------------------
ES JVM 设置
JVM参数
ES默认值
环境变量名
-Xms
256m
-Xmx
1g
-Xms and –Xmx
-Xmn
-XX:MaxDirectMemorySize
-Xss
256k
-XX:UseParNewGC
+
-XX:UseConcMarkSweepGC
+
-XX:CMSInitiatingOccupancyFraction
75
75
-XX:UseCMSInitiatingOccupancyOnly
-XX:UseCondCardMark
我们可以注意到ES JVM Heap内存设置为在256M在1GB之间.
这个设置是为在开发和示范环境中使用的,开发人员可以通过简单地安装ES就可以使用了,但是这样的内存设置在很多情况下都是不够用的,我在需要设置更大的值。
ES_MIN_MEM/ES_MAX_MEM 用于控制jvm的堆内存,另外还有ES_HEAP_SEIZ,这样我可以设置更多的堆内存用于ES,另外建议不在启动内存堆平衡,因为这样会浪费很大的性能。
ES_HEAP_NEWSIZE这个参数用于控制堆内存的子集,即新生代堆控制
ES_DIRECT_SIZE,我们可以对应到Direct Memory Size这个参数,在JVM管理数据中使用的是NIO,本机内存可以映射到虚拟地址空间,在X64的架构上更有效,在ES中没有选择进行设置,但是有一个问题,本机直接内存的分配不会受到Java堆大小的限制,但是即然是内存那肯定还是要受到本机物理内存(包括SWAP区或者Windows虚拟内存)的限制的,一般服务器管理员配置JVM参数时,会根据实际内存设置-Xmx等参数信息,但经常忽略掉直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),而导致动态扩展时出现OutOfMemoryError异常。
下面例出一些JVM参数设置
JVM parameter Garbage collector
-XX:+UseSerialGC serial collector
-XX:+UseParallelGC parallel collector
-XX:+UseParallelOldGC Parallel compacting collector
-XX:+UseConcMarkSweepGC Concurrent-Mark-Sweep ( CMS ) collector
-XX:+UseG1GC Garbage-First collector (G1)
UseParNewGC和UseConcMarkSweepGC是结并并行和行发性的垃圾回收机制,在JAVA6中将默认为UserParNewGC和UseGoncMarkSweepGC并禁用串行收集器.
UseCondCardMark 将在在高度并发的情况下,将些值注释掉
总结:
1、修改MAX 和MIN Heap大小设置。
2、设置垃圾回收百分比
3、如果在JAVA7中禁用默认的G1垃圾回收机制。
JVM内存分为如下几段:
JVM CODE用于内部代码存放
Noe-heap memory用于加载类
Stack memory 用于存放本地变量和线程操作数
Heap memory 存放引用类型对象
Direct Buffer,缓冲输入,输出数据
Heap memory大小设置是非常重要的,因为java的运行取决于一个合理的heap的大小,如果设置太小,在许多垃圾回收或是高性能的情况下就会出现OutOfMemory异常。如果堆太大,垃圾回收将需要更大的数据,该算法将要面对更高数量的存活堆,这样操作系统也会面对较大的压力。
Non-heap内存分配是由java应用程序自动设置的,没有办法控制这个参数,因为它是由JAVA应用程序代码决定的。
垃圾回收与Lucene段
在ES中的垃圾回收器是集用的CMS垃圾回收,这种回收器不是提高敢回收的效率可是降低了回收的次数,但是面对比较大的数据集合时,这种回收可能需要的时间更长。
而这种大的数据集合主要是在Lucene的索引中,因些可以将索引的段进行一行调优工作,提高GC的效率。
index.merge.policy.segments_per_tier
减少分页
在大堆内存的情况下,如果内存不足时会与操作系统的SWAP空间进行分页数据的交换,但是这种交换是非常慢的,这种会降低整体性能。
垃圾回收器的选择
JAVA 7中的默认是G1垃圾回收器,这种回收器和CMS回收相对,他在于处理吞吐量,但是如果在大堆的情况下CMS回收器在性能上将超过G1.
性能调优策略
1、 收集日志
2、 对日志进行分析
3、 选择你要优化的目标
4、 计划优化
5、 应用新有设置
6、 监控程序在新设置后的运行情况
7、 反复试尝
ES 垃圾回收日志格式
将日志等级调用警告在垃圾回收时你能看到如下信息:
LogFile
说明
Gc
垃圾回收运行
ParNew
新生代垃圾回收器
duration 2.6m
垃圾回收花费时间
collections [1]/[2.7m]
一个收集器运行花费2.7M
memory [2.4gb]
预设2.4GB
[2.3gb]/[3.8gb]
现在使用2.3GB/总共3.8GB
Code Cache [13.7mb]->[13.7mb]/[48mb]
代码缓存
Par Eden Space [109.6mb]->[15.4mb]/[1gb]
Par Eden Space使用空间
Par Survivor Space[136.5mb]->[0b]/[136.5mb]
Par Survivor Space
CMS Old Gen [2.1gb]->[2.3gb]/[2.6gb]
CMS Old Gen
CMS Perm Gen [35.1mb]->[34.9mb]/[82mb]
CMS Perm Gen
建议:
1、ES不要运行在6U22之前因之多版本的JDK存在许多的bug,尽量使用Sun/Oracle比较最出的JDK6-7因为里面修复很多bug.
如果在JAVA7正式发布的情况下最好使用JDK7(不过要到2013了)
2、考虑到ES是一个比较新的软件,利用最先的技术来获取性能,尽量从JVM中来挤压性能,另外检索您的操作系统是否是最新版的,尽量使用最新版的操作系统。
3、做好随时更新JAVA版本和ES的版本的情况,因为每季度或是每年都会有新的版本出来。所以在做好版本更新的准备
4、测试从小到大,因为ES的强在多个节点的部署,一个节点是不足以测试出其性能,一个生产系统至少在三个节点以上。
5、测试JVM
6、如果索引有更新请记住对索引段的操作(index.merge.policy.segments_per_tier)
7、在性能调优之前,请先确定系统的最大性能和最大吞吐量
8、启用日志记录对JAVA垃圾回怍机制,有助于更好的诊断,以至于来调整你的系统
9、提高CMS垃圾收集器,您可以添加一个合理的- xx:CMSWaitDuration参数
10、如果堆大小趣过6-8GB,请选择使用CMS
-----------------------------------------------
ElasticSearch教程(3)——ElasticSearch的插件
更多 0
插件 ElasticSearch 教程
插件作为一种普遍使用的,用来增强原系统核心功能的机制,得到了广泛的使用,elasticsearch也不例外。
1. 安装elasticsearch插件
从0.90.2安装其实很简单,有三种方式,
1.1 在确保你网络顺畅的情况下,执行如下格式的命令即可:
plugin --install <org>/<user/component>/<version>
具体的<org>/<user/component>/<version>可参加各插件的使用说明。
1.2 如果网络不太顺畅,可以下载好插件的压缩包后以如下方式安装:
bin/plugin --url file://path/to/plugin --install plugin-name
1.3 你也可以直接将插件的相关文件拷贝到plugins目录下面,需要注意的是,这种方式需要特别留意插件的种类。
2. 如何查看当前已经加载的插件
curl -XGET 'http://localhost:9200/_nodes/plugin'
或者可以指定某个实例
curl -XGET 'http://localhost:9200/_nodes/10.0.0.1/plugin'
3. 个人强力推荐的插件
要想知道整个插件的列表,请访问http://www.elasticsearch.org/guide/reference/modules/plugins/ 插件还是很多的,个人认为比较值得关注的有以下几个,其他的看你需求,比如你要导入数据当然就得关注river了。
3.1 BigDesk
该插件可以查看集群的jvm信息,磁盘IO,索引创建删除信息等,适合查找系统瓶颈,监控集群状态等,可以执行如下命令进行安装,或者访问项目地址:https://github.com/lukas-vlcek/bigdesk
bin/plugin -install lukas-vlcek/bigdesk
说明:ElasticSearch HQ功能跟这个插件也很强大。
3.2 Head
可以查看索引情况,搜索索引,查看集群状态和分片分布等,可以执行如下命令进行安装,或者访问项目地址:https://github.com/mobz/elasticsearch-head
bin/plugin -install mobz/elasticsearch-head
3.3 elasticsearch中文分词插件
官方的中文分词插件:Smart Chinese Analysis Plugin
Medcl开发的中午分词插件: IK Analysis Plugin 以及 Pinyin Analysis Plugin
3.4 ZooKeeper Discovery Plugin
elasticsearch 默认是使用Zen作为集群发现和存活管理的,ZooKeeper作为一个分布式高可用性的协调性系统,在这方面有着天然的优势,如果你比较信任zookeeper,那么你可以使用这个插件来替代Zen。
总结:本文主要介绍了elasticsearch的插件安装方法,如何查看当前加载的插件的方法,以及个人认为比较值得关注的一些插件。