博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ElasticSearch学习
阅读量:6049 次
发布时间:2019-06-20

本文共 15717 字,大约阅读时间需要 52 分钟。

前言:ES学习可参考 ,这个在线电子书内容介绍的很是详细。

本文使用的ElasticSearch版本是 2.4.2

官网 

中文社区 

 

 

目录

  • Elastic系配套组件

 

 

安装

首先我们需要去官网下载安装包  

解压后结构是这样的(2.5以上版本会有plugins目录,没有的需要手动创建)

 

创建一个es用户(因为es不允许使用root用户启动)

useradd es

 

将该目录权限修改为es用户所有

chown es:es -hR .

 

所有要作为es节点的机器都要执行以上操作

 

安装插件

ES的插件都是要安装到 es安装目录/plugins/ 下

官网插件地址 :

1.elasticsearch-head

这是一个elasticsearch的集群管理工具,它是完全由HTML5编写的独立网页程序,通过这个插件可以可视化监控ES。

我使用的是版本2.4.2,安装起来很是简单,在ES根目录下执行 

bin/plugin install mobz/elasticsearch-head

成功之后在页面上访问 http://192.168.0.39:9200/_plugin/head/ 即可。

其他版本或者更多详情,参考官网:

 

ES5以后就不能用安装的方式启动head插件了,除了安装之外,还需要在elasticsearch.yml里面增加:

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

 

2.中文分词器 ik

官网 

下载源码之后进行解压

然后用maven编译

maven package

 

成功后安装包在target/releases/elasticsearch-analysis-ik-x.x.x.zip

将这个压缩包解压到es的插件的对应目录下即可(plugins/ik)。

最后 重启ES集群

 

3.elasticsearch-analysis-pinyin 分词器

4.nGram

我们用ik分词器的时候,检索的时候会把搜索词进行分词然后检索。如

搜索 “我们的生活”,优先是包含这5个字的,但是也会返回包含“我们”和“生活”的数据。

但是有时候我们不需要这么智能,只需要完全匹配的进行搜索。这就需要用到ngram了。(不需要单独安装,只需要设置settings即可)

先上一个例子

POST url : localhost:9200/ngramtestContent-Type: application/json{    "settings": {        "analysis": {            "analyzer": {                "charSplit": {                    "type": "custom",                     "tokenizer": "my_ngram_tokenizer",                    "filter":["lowercase"]                }            },            "tokenizer": {                "my_ngram_tokenizer": {                    "type": "nGram",                     "min_gram": "2",                     "max_gram": "4",                     "token_chars": ["letter","digit","punctuation"]                }            }        }    },     "mappings": {        "myType": {            "dynamic": "strict",             "properties": {                "content": {                    "type": "string",                     "analyzer": "charSplit",                     "search_analyzer": "charSplit"                }            }        }    }}

 

 

属性settings.analysis.tokenizer下面的 my_ngram_tokenizer 对象是自定义的tokenizer

settings.analysis.analyzer.charSplit 则是基于 my_ngram_tokenizer 的自定义分词器

关于my_ngram_tokenizer 中的属性:

min_gram:单个词的最小长度,默认1max_gram:单个词的最大长度,默认2token_chars:可以接受的字符集(即遇到不在列表中的字符集会进行文本分割)字符集包括letter           字母或汉字  a, b, ï or 京digit            数字 3 or 7whitespace       空白(空格、回车、tab等)  " " or "\n"punctuation      标点符号  ! , 。or "symbol           标志(区别于标点符号) $ or √

 

 

可以从下面的例子了解一下

配置片段 "token_chars": ["letter","digit","punctuation"]

即接收文字数字和标点,那现在我在内容中添加symbol标记 $

POST 192.168.5.222:9200/yuqingtest/_analyze?pretty&analyzer=charSplit商业核心和$标准化技术

 

 返回结果

{  "tokens": [    {      "token": "商业核",      "start_offset": 0,      "end_offset": 3,      "type": "word",      "position": 0    },    {      "token": "商业核心",      "start_offset": 0,      "end_offset": 4,      "type": "word",      "position": 1    },    {      "token": "业核心",      "start_offset": 1,      "end_offset": 4,      "type": "word",      "position": 2    },    {      "token": "业核心和",      "start_offset": 1,      "end_offset": 5,      "type": "word",      "position": 3    },    {      "token": "核心和",      "start_offset": 2,      "end_offset": 5,      "type": "word",      "position": 4    },    {      "token": "标准化",      "start_offset": 6,      "end_offset": 9,      "type": "word",      "position": 5    },    {      "token": "标准化技",      "start_offset": 6,      "end_offset": 10,      "type": "word",      "position": 6    },    {      "token": "准化技",      "start_offset": 7,      "end_offset": 10,      "type": "word",      "position": 7    },    {      "token": "准化技术",      "start_offset": 7,      "end_offset": 11,      "type": "word",      "position": 8    },    {      "token": "化技术",      "start_offset": 8,      "end_offset": 11,      "type": "word",      "position": 9    }  ]}

 

可以看到$分割开了左右的词

5. delete-by-query

ES的条件删除API从2.0开始就已经被删掉了,之后版本只能通过安装插件的方式进行条件删除。

bin/plugin install delete-by-query

注:集群环境下必须在每个结点上安装且重启结点后插件才会生效。

使用方式跟2.0以前的版本一样。

 

 

 

配置

ES的配置除了一些必要的选项,其他的不要修改,因为能优化的地方官方都已经优化了,如果改了反而可能引起各种问题。 

配置文件只需要改动config/elasticsearch.yml 的4个地方即可

...cluster.name: my-es-cluster...node.name: node1...network.host: 192.168.245.139...
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping.unicast.hosts: ["192.168.0.37", "192.168.0.38","192.168.0.39"]

要注意的是  yml类型的配置文件  冒号后面必须要有一个空格  否则读取的时候会认为格式不正确。

discovery.zen.ping.unicast.hosts 是指定Master的备选节点;如果不添加这一行,那将成为单点的ES。

 

其他可改动项:

①路径

默认情况下, Elasticsearch 会把插件、日志以及你最重要的数据放在安装目录下。这会带来不幸的事故, 如果你重新安装 Elasticsearch 的时候不小心把安装目录覆盖了,你就可能把你的全部数据删掉了。

最好的选择就是把你的数据目录配置到安装目录以外的地方, 同样你也可以选择转移你的插件和日志目录。

#注意:你可以通过逗号分隔指定多个目录。 path.data: /path/to/data1,/path/to/data2 # Path to log files:path.logs: /path/to/logs# Path to where plugins are installed:path.plugins: /path/to/plugins

 

②脑裂相关

ES集群中Master承担了更大的请求和计算压力,如果Master崩了的话,会出现脑裂问题(Split Brain)

所以我们进行职责分离:

指定若干节点只作为Master,添加配置

node.master: truenode.data: false

其他的作为DataNode,添加配置

node.master: falsenode.data: true

改变发现机制

discovery.zen.ping.multicast.enabled: false

延长主节点发现时间(确定Master失联的时间间隔)

discovery.zen.ping_timeout: 3

 

 

 

参考:

 
③最小主节点数
 
该设定对集群的稳定 
极其重要。 当你的集群中有两个主节点的时候,这个配置有助于防止脑裂
取值算法: ( master 候选节点个数 / 2) + 1 ,例如有3个master候选节点的话:
discovery.zen.minimum_master_nodes: 2

 

 

启动

#先进入ES安装路径su es //切换到之前创建的es用户bin/elasticsearch#bin/elasticsearch -d(也可以后台运行) 关闭
kill `jps |grep Elasticsearch |cut -c1-5`
 

 

在浏览器上输入 

{  "name" : "myhost",  "cluster_name" : "my-es-cluster",  "cluster_uuid" : "UZHnaRT7R06kBjKh6Qbzvg",  "version" : {    "number" : "2.4.2",    "build_hash" : "161c65a337d4b422ac0c805f284565cf2014bb84",    "build_timestamp" : "2017-03-17T11:51:03Z",    "build_snapshot" : false,    "lucene_version" : "5.5.2"  },  "tagline" : "You Know, for Search"}

看到以上结构内容则表明安装配置成功 

 

 

CURL命令

cluster

#查看集群健康状态 http://192.168.0.37:9200/_cluster/health #集群统计 http://192.168.0.37:9200/_cluster/stats #健康状况(分片级别) http://192.168.0.45:9200/_cluster/health?level=shards #查看资源占用情况(还有更多参数可设置) localhost:9200/_cat/nodes?v&h=host,heap.current,heap.percent,heap.max,ram.max,disk.avail,node.role,m

  

index

#创建indexcurl -XPUT http://192.168.5.222:9200/index_name/#删除indexcurl -XDELETE http://192.168.5.222:9200/index_name/#查看indexcurl -XGET http://192.168.5.222:9200/index_name/

 

 

type

#新增/更新Type(不在url的最后指定id的话,es会自动生成id)curl -XPOST http://192.168.5.222:9200/index_name/emp/1 -d '{"first_name" : "John","age" : 25,"about" : "I love to go rock climbing","interests": ["sports","music"]}'#检索Typecurl -XGET http://192.168.5.222:9200/index_name/emp/1?pretty#查询所有字段curl –XGET http://192.168.5.222:9200/index_name/emp/1/_source#只返回部分字段curl -XGET http://192.168.5.222:9200/index_name/emp/1?_source=name,age#返回所有数据curl -XGET http://192.168.5.222:9200/index_name/emp/_search#简单的条件查询curl -XGET http://192.168.5.222:9200/index_name/emp/_search?q=first_name:Smith#根据ID删除curl -XDELETE http://192.168.5.222:9200/index_name/emp/1#条件删除curl -XDELETE 'http://localhost:9200/index_name/emp,user/_query?q=user:kimchy'#清空表数据curl -X DELETE http://192.168.0.39:9200/
/
/_query -d '{"query": {"match_all": {}}}'#查看分词情况curl -XPOST http://192.168.5.222:9200/index_name/_analyze?pretty&analyzer=charSplit -d '商业核心和$标准化技术'

 

 

 

type的复杂查询(DSL),这种查询同时支持GET和POST,不过使用CURL命令来POST数据太不直观,我都是使用Postman

#新增type

POST 192.168.5.222:9200/yuqingtest/article/Content-Type: application/json{    "title" : "政协副主席建议提高境外黑匣子",    "content" : "使用了商业核心和$标准化技术,相比以前的非标$准化方案,更容易维护和支持哈哈有个黑匣子在外面。"}

 

#查询(查询相关语句太多)

{  "query": {    "multi_match": {      "query": "黑匣子",      "type": "phrase",      "slop": 1,      "fields": [        "content"      ],      "max_expansions": 1    }  },    "highlight" : {        "pre_tags" : ["
", "
"], "post_tags" : ["
", ""], "fields" : { "content" : {} } }, "sort":{ "createTime":{"order":"esc"} }}

 

 

 

JAVA API

ES官方提供的Javaapi用起来不是很方便(org.elasticsearch.elasticsearch)

官方Java Api文档地址:

用spring的封装版就好得多(org.springframework.data.spring-data-elasticsearch),尤其是结合springboot后,精简了配置等相关操作,开发效率更是提升

pom的依赖以及配置参考 ,下面只看重点

略过ArticleEntity

Repo

public interface ArticleRepository extends ElasticsearchRepository
{}

 

增删改查例子

package com.ray.estest;import java.util.ArrayList;import java.util.List;import java.util.Map;import org.elasticsearch.action.search.SearchResponse;import org.elasticsearch.index.query.BoolQueryBuilder;import org.elasticsearch.index.query.QueryBuilders;import org.elasticsearch.index.query.RangeQueryBuilder;import org.elasticsearch.search.SearchHit;import org.elasticsearch.search.highlight.HighlightBuilder.Field;import org.elasticsearch.search.highlight.HighlightField;import org.elasticsearch.search.sort.SortBuilder;import org.elasticsearch.search.sort.SortBuilders;import org.elasticsearch.search.sort.SortOrder;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;import org.springframework.data.elasticsearch.core.SearchResultMapper;import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;import org.springframework.data.elasticsearch.core.query.SearchQuery;import com.product.yq_common.utils.StringUtils;import com.product.yq_service.entity.input.ArticleDetailInput;import com.product.yq_service.entity.input.ArticleQueryEntity;import com.product.yq_service.entity.output.ArticleSummaryInfoEntity;import com.product.yq_serviceimpl.entity.ArticleEntity;import com.product.yq_serviceimpl.repo.ArticleRepository;/** * @author Ray * 2017年3月30日 */public class ArticleServiceImpl {    @Autowired    private ArticleRepository repo;    @Autowired    private ElasticsearchTemplate elasticsearchTemplate;    public Object getArticles(ArticleQueryEntity entity) throws Exception {        List
articles = new ArrayList
(); // 分页 Pageable pager = new PageRequest(0, 10); // 构建查询语句 BoolQueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("deleted", false)) .must(QueryBuilders.termQuery("name", "Zhang"))// term一般用于not_analyzed .must(QueryBuilders.matchQuery("favorite", entity.getType()));// match则用于analyzed // 拼接条件 if (!StringUtils.isEmpty(entity.getSearchWord())) { // multiMatchQuery 混合查询 同时检索多个字段 qb = qb.must(QueryBuilders.multiMatchQuery(entity.getSearchWord(), "title", "summary")); } if (!StringUtils.isEmpty(entity.getStartDate()) || !StringUtils.isEmpty(entity.getEndDate())) { // 区间查询 gt,lt,gte,lte,from-to, RangeQueryBuilder rqb = QueryBuilders.rangeQuery("createDate"); if (!StringUtils.isEmpty(entity.getStartDate())) { rqb = rqb.gte(entity.getStartDate()); } if (!StringUtils.isEmpty(entity.getEndDate())) { rqb = rqb.lte(entity.getEndDate()); } qb = qb.must(rqb); } // 排序(最好不要用字符串类型的Field做排序) SortBuilder sort = SortBuilders.fieldSort("createTime").order(SortOrder.DESC); // 开始组装 SearchQuery query = new NativeSearchQueryBuilder().withQuery(qb).withSort(sort).withPageable(pager).build(); // 返回的是带有分页数据的对象 Page
entities = repo.search(query); long total = entities.getTotalElements(); int pages = entities.getTotalPages(); List
rst = entities.getContent(); return rst; } /** * 更新 */ public void update(ArticleDetailInput entity) throws Exception { ArticleEntity oriES = repo.findOne(entity.getArticleId()); oriES.setTitle(entity.getTitle()); oriES.setContent(entity.getContent()); repo.save(oriES); } /** * 添加 */ public String add(ArticleDetailInput entity) throws Exception { ArticleEntity oriES = new ArticleEntity(); oriES.setTitle("这是title"); oriES.setContent("这是content"); oriES = repo.save(oriES); return oriES.getArticleId();// articleId映射ES中的ID } /** * 获取详情 */ public Object detail(String id) throws Exception { return repo.findOne(id); } /** * 删除 */ public void delete(String id) throws Exception { repo.delete(id); } /** * 根据关键词进行搜索并返回高亮内容 */ public Object searchByWords(String word) throws Exception { List
articles = new ArrayList
(); Pageable pager = new PageRequest(0, 10); // 构建查询语句 BoolQueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("deleted", false)) .must(QueryBuilders.multiMatchQuery(word, "title", "content")); String preTags = "
"; String postTags = ""; // 设置要高亮的字段,高亮的前后标签,高亮内容的截取长度 Field fTitle = new Field("title").preTags(preTags).postTags(postTags).fragmentSize(100); Field fContent = new Field("content").preTags(preTags).postTags(postTags).fragmentSize(100); SearchQuery query = new NativeSearchQueryBuilder().withQuery(qb).withPageable(pager) .withHighlightFields(fTitle, fContent).build(); elasticsearchTemplate.queryForPage(query, ArticleEntity.class, new SearchResultMapper() { @SuppressWarnings("unchecked") @Override public
AggregatedPage
mapResults(SearchResponse response, Class
clazz, Pageable pageable) { // 总个数 long total = response.getHits().getTotalHits(); // 总页数 int pages = (int) Math.ceil((double) total / pager.getPageSize()); if (response.getHits().getTotalHits() <= 0) { return null; } for (SearchHit searchHit : response.getHits()) { ArticleSummaryInfoEntity item = new ArticleSummaryInfoEntity(); articles.add(item); Map
source = searchHit.getSource(); item.setArticleId(source.get("articleId").toString()); Map
highlightFields = searchHit.getHighlightFields(); // 查看高亮字段是否命中 HighlightField hlTitleField = highlightFields.get("title"); if (hlTitleField != null && hlTitleField.fragments() != null) { item.setTitle((hlTitleField.fragments()[0].string())); } else { item.setTitle((String) source.get("title")); } HighlightField hlContentField = highlightFields.get("content"); if (hlContentField != null && hlContentField.fragments() != null) { item.setSummary(hlContentField.fragments()[0].string()); } else { item.setSummary((String) source.get("summary")); } } return new AggregatedPageImpl
((List
) articles); } }); return articles; }}

  

如果使用ngram让部分字段实现完全匹配查询,除了要设置要mappings,java代码中也会有点小改动:给QueryBuilder设置slop和type

......// 构建查询语句BoolQueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.multiMatchQuery(search, "content").slop(1).type(Type.PHRASE));......

 

与大数据组件的结合使用

ES官方提供一个ES与hadoop组件连接器(ES-Hadoop)

这些组件包括HDFS、Spark、Storm、Hive、Pig、MapReduce、Cascading

该连接器支持各种版本的Hadoop(CDH, MapR, HDP)

要注意的是,这个连接器并不需要以插件的形式安装,只是提供Hadoop与ES交互的Jar包。

 

Elastic系配套组件

Kibana

ES中数据可视化的组件,十分强大。在可视化方面,支持多种数据模型(地图、时间序列、graph、机器学习等);同时在一定程度上还支持ES的管理和安全

LogStash 

数据处理管道,能够同时 从多个来源采集数据、转换数据,然后将数据发送到存储库(当然大部分是存到ES中)。

管道中可指定过滤器以过滤解析数据,官方提供了以处理各种数据

ES-Hadoop

参考 

X-Pack security (由X-Pack提供)

 维护Elastic Stack中的安全权限

Beats

轻量型数据采集器,集合了多种单一用途数据采集器。这些采集器安装后可用作轻量型代理,从成百上千或成千上万台机器向 Logstash 或 Elasticsearch 发送数据。

这些单用途采集器包括:

FileBeat(日志)、MetricBeat(指标)、PacketBeat(网络)、WinlogBeat(Windows事件日志)、AuditBeat(审计日志)、HeartBeat(运行时间监控)

由于这些采集器使用通用接口,且底层都是基于libbeat进行数据转发,所以采集器的扩展变得简单。

 

 

 

其他

1.ES的文件存储结构与hadoop十分类似,二者可以搭配使用,详情参阅

2.当出现Unassigned分片时,我们可以通过分片重分配解决这个问题

curl -X PUT http://192.168.0.37:9200/_cluster/settings \  -d '{
"transient": { "cluster.routing.allocation.enable": "all" }}'

 3.如果是用spring-data-elasticsearch访问es服务,那么必须二者版本要对应起来,2.x版本的es对应springboot1.5*,2+版本的es对应springboot 2*

 

 

参考:

 

转载于:https://www.cnblogs.com/TiestoRay/p/6634160.html

你可能感兴趣的文章
[ffmpeg]通过Qt调用ffmpeg命令
查看>>
决心书
查看>>
Android音乐播放器的开发实例
查看>>
Android Camera 使用小结
查看>>
流控算法
查看>>
带你认识OSI,network就靠它
查看>>
【小松教你手游开发】【面试必读(编程基础)】C# 理解泛型
查看>>
Pyton学习—循环语句
查看>>
MES制造执行系统
查看>>
了解java虚拟机&mdash;堆相关参数设置(3)
查看>>
ArrayList 源码
查看>>
2018阿里云云数据库RDS核心能力演进
查看>>
Vsftp基于mysql实现账号认证
查看>>
区块链中的密码学(3):椭圆曲线加密分析
查看>>
动态代理的几种方式
查看>>
https证书申请价格
查看>>
REDHAT RHEL 6环境下如何配置YUM源
查看>>
租用邮箱or自建邮件系统,如何选择?
查看>>
内存溢出
查看>>
PYTHON 多线程信号量
查看>>