一、简介

ElasticSearch和Solr都是基于Lucene的搜索引擎,不过ElasticSearch天生支持分布式,而Solr是4.0版本后的SolrCloud才是分布式版本,Solr的分布式支持需要ZooKeeper的支持。

这里有一个详细的ElasticSearch和Solr的对比:http://solr-vs-elasticsearch.com/

二、基本用法

集群(Cluster): ES是一个分布式的搜索引擎,一般由多台物理机组成。这些物理机,通过配置一个相同的cluster name,互相发现,把自己组织成一个集群。

节点(Node):同一个集群中的一个Elasticsearch主机。

Node类型:

1)data node: 存储index数据。Data nodes hold data and perform data related operations such as CRUD, search, and aggregations.

2)client node: 不存储index,处理转发客户端请求到Data Node。

3)master node: 不存储index,集群管理,如管理路由信息(routing infomation),判断node是否available,当有node出现或消失时重定位分片(shards),当有node failure时协调恢复。(所有的master node会选举出一个master leader node)

详情参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html

主分片(Primary shard):索引(下文介绍)的一个物理子集。同一个索引在物理上可以切多个分片,分布到不同的节点上。分片的实现是Lucene 中的索引。

注意:ES中一个索引的分片个数是建立索引时就要指定的,建立后不可再改变。所以开始建一个索引时,就要预计数据规模,将分片的个数分配在一个合理的范围。

副本分片(Replica shard):每个主分片可以有一个或者多个副本,个数是用户自己配置的。ES会尽量将同一索引的不同分片分布到不同的节点上,提高容错性。对一个索引,只要不是所有shards所在的机器都挂了,就还能用。

索引(Index):逻辑概念,一个可检索的文档对象的集合。类似与DB中的database概念。同一个集群中可建立多个索引。比如,生产环境常见的一种方法,对每个月产生的数据建索引,以保证单个索引的量级可控。

类型(Type):索引的下一级概念,大概相当于数据库中的table。同一个索引里可以包含多个 Type。

文档(Document):即搜索引擎中的文档概念,也是ES中一个可以被检索的基本单位,相当于数据库中的row,一条记录。

字段(Field):相当于数据库中的column。ES中,每个文档,其实是以json形式存储的。而一个文档可以被视为多个字段的集合。比如一篇文章,可能包括了主题、摘要、正文、作者、时间等信息,每个信息都是一个字段,最后被整合成一个json串,落地到磁盘。

映射(Mapping):相当于数据库中的schema,用来约束字段的类型,不过 Elasticsearch 的 mapping 可以不显示地指定、自动根据文档数据创建。

Elasticsearch集群可以包含多个索引(indices),每一个索引可以包含多个类型(types),每一个类型包含多个文档(documents),然后每个文档包含多个字段(Fields),这种面向文档型的储存,也算是NoSQL的一种吧。

ES比传统关系型数据库,对一些概念上的理解:

Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices   -> Types  -> Documents -> Fields

从创建一个Client到添加、删除、查询等基本用法:

1、创建Client

public ElasticSearchService(String ipAddress, int port) {client = new TransportClient().addTransportAddress(new InetSocketTransportAddress(ipAddress,port));}

这里是一个TransportClient。

ES下两种客户端对比:

TransportClient:轻量级的Client,使用Netty线程池,Socket连接到ES集群。本身不加入到集群,只作为请求的处理。

Node Client:客户端节点本身也是ES节点,加入到集群,和其他ElasticSearch节点一样。频繁的开启和关闭这类Node Clients会在集群中产生“噪音”。

2、创建/删除Index和Type信息

    // 创建索引public void createIndex() {client.admin().indices().create(new CreateIndexRequest(IndexName)).actionGet();}// 清除所有索引public void deleteIndex() {IndicesExistsResponse indicesExistsResponse = client.admin().indices().exists(new IndicesExistsRequest(new String[] { IndexName })).actionGet();if (indicesExistsResponse.isExists()) {client.admin().indices().delete(new DeleteIndexRequest(IndexName)).actionGet();}}// 删除Index下的某个Typepublic void deleteType(){        client.prepareDelete().setIndex(IndexName).setType(TypeName).execute().actionGet();}// 定义索引的映射类型public void defineIndexTypeMapping() {try {XContentBuilder mapBuilder = XContentFactory.jsonBuilder();mapBuilder.startObject().startObject(TypeName).startObject("_all").field("enabled", false).endObject().startObject("properties").startObject(IDFieldName).field("type", "long").endObject().startObject(SeqNumFieldName).field("type", "long").endObject().startObject(IMSIFieldName).field("type", "string").field("index", "not_analyzed").endObject().startObject(IMEIFieldName).field("type", "string").field("index", "not_analyzed").endObject().startObject(DeviceIDFieldName).field("type", "string").field("index", "not_analyzed").endObject().startObject(OwnAreaFieldName).field("type", "string").field("index", "not_analyzed").endObject().startObject(TeleOperFieldName).field("type", "string").field("index", "not_analyzed").endObject().startObject(TimeFieldName).field("type", "date").field("store", "yes").endObject().endObject().endObject().endObject();PutMappingRequest putMappingRequest = Requests.putMappingRequest(IndexName).type(TypeName).source(mapBuilder);client.admin().indices().putMapping(putMappingRequest).actionGet();} catch (IOException e) {log.error(e.toString());}

这里自定义了某个Type的索引映射(Mapping):

1)默认ES会自动处理数据类型的映射:针对整型映射为long,浮点数为double,字符串映射为string,时间为date,true或false为boolean。

2)字段的默认配置是indexed,但不是stored的,也就是 field("index", "yes").field("store", "no")。

3)这里Disable了“_all”字段,_all字段会把所有的字段用空格连接,然后用“analyzed”的方式index这个字段,这个字段可以被search,但是不能被retrieve。

4)针对string,ES默认会做“analyzed”处理,即先做分词、去掉stop words等处理再index。如果你需要把一个字符串做为整体被索引到,需要把这个字段这样设置:field("index", "not_analyzed")。

5)默认_source字段是enabled,_source字段存储了原始Json字符串(original JSON document body that was passed at index time)。

详情参考:

https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping-intro.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-store.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-all-field.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html

3、索引数据

    // 批量索引数据public void indexHotSpotDataList(List<Hotspotdata> dataList) {if (dataList != null) {int size = dataList.size();if (size > 0) {BulkRequestBuilder bulkRequest = client.prepareBulk();for (int i = 0; i < size; ++i) {Hotspotdata data = dataList.get(i);String jsonSource = getIndexDataFromHotspotData(data);if (jsonSource != null) {bulkRequest.add(client.prepareIndex(IndexName, TypeName,data.getId().toString()).setRefresh(true).setSource(jsonSource));}}BulkResponse bulkResponse = bulkRequest.execute().actionGet();if (bulkResponse.hasFailures()) {Iterator<BulkItemResponse> iter = bulkResponse.iterator();while (iter.hasNext()) {BulkItemResponse itemResponse = iter.next();if (itemResponse.isFailed()) {log.error(itemResponse.getFailureMessage());}}}}}}// 索引数据public boolean indexHotspotData(Hotspotdata data) {String jsonSource = getIndexDataFromHotspotData(data);if (jsonSource != null) {IndexRequestBuilder requestBuilder = client.prepareIndex(IndexName,TypeName).setRefresh(true);requestBuilder.setSource(jsonSource).execute().actionGet();return true;}return false;}// 得到索引字符串public String getIndexDataFromHotspotData(Hotspotdata data) {String jsonString = null;if (data != null) {try {XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();jsonBuilder.startObject().field(IDFieldName, data.getId()).field(SeqNumFieldName, data.getSeqNum()).field(IMSIFieldName, data.getImsi()).field(IMEIFieldName, data.getImei()).field(DeviceIDFieldName, data.getDeviceID()).field(OwnAreaFieldName, data.getOwnArea()).field(TeleOperFieldName, data.getTeleOper()).field(TimeFieldName, data.getCollectTime()).endObject();jsonString = jsonBuilder.string();} catch (IOException e) {log.equals(e);}}return jsonString;}

ES支持批量和单个数据索引。

4、查询获取数据

    // 获取少量数据100个private List<Integer> getSearchData(QueryBuilder queryBuilder) {List<Integer> ids = new ArrayList<>();SearchResponse searchResponse = client.prepareSearch(IndexName).setTypes(TypeName).setQuery(queryBuilder).setSize(100).execute().actionGet();SearchHits searchHits = searchResponse.getHits();for (SearchHit searchHit : searchHits) {Integer id = (Integer) searchHit.getSource().get("id");ids.add(id);}return ids;}// 获取大量数据private List<Integer> getSearchDataByScrolls(QueryBuilder queryBuilder) {List<Integer> ids = new ArrayList<>();// 一次获取100000数据SearchResponse scrollResp = client.prepareSearch(IndexName).setSearchType(SearchType.SCAN).setScroll(new TimeValue(60000)).setQuery(queryBuilder).setSize(100000).execute().actionGet();while (true) {for (SearchHit searchHit : scrollResp.getHits().getHits()) {Integer id = (Integer) searchHit.getSource().get(IDFieldName);ids.add(id);}scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();if (scrollResp.getHits().getHits().length == 0) {break;}}return ids;}

这里的QueryBuilder是一个查询条件,ES支持分页查询获取数据,也可以一次性获取大量数据,需要使用Scroll Search。

5、聚合(Aggregation Facet)查询

    // 得到某段时间内设备列表上每个设备的数据分布情况<设备ID,数量>public Map<String, String> getDeviceDistributedInfo(String startTime,String endTime, List<String> deviceList) {Map<String, String> resultsMap = new HashMap<>();QueryBuilder deviceQueryBuilder = getDeviceQueryBuilder(deviceList);QueryBuilder rangeBuilder = getDateRangeQueryBuilder(startTime, endTime);QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(deviceQueryBuilder).must(rangeBuilder);TermsBuilder termsBuilder = AggregationBuilders.terms("DeviceIDAgg").size(Integer.MAX_VALUE).field(DeviceIDFieldName);SearchResponse searchResponse = client.prepareSearch(IndexName).setQuery(queryBuilder).addAggregation(termsBuilder).execute().actionGet();Terms terms = searchResponse.getAggregations().get("DeviceIDAgg");if (terms != null) {for (Terms.Bucket entry : terms.getBuckets()) {resultsMap.put(entry.getKey(),String.valueOf(entry.getDocCount()));}}return resultsMap;}

Aggregation查询可以查询类似统计分析这样的功能:如某个月的数据分布情况,某类数据的最大、最小、总和、平均值等。

详情参考:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-aggs.html

三、集群配置

配置文件elasticsearch.yml

集群名和节点名:

#cluster.name: elasticsearch

#node.name: "Franz Kafka"

是否参与master选举和是否存储数据

#node.master: true

#node.data: true

分片数和副本数

#index.number_of_shards: 5
#index.number_of_replicas: 1

允许其他网络访问:

network.host: 0

master选举最少的节点数,这个一定要设置为整个集群节点个数的一半加1,即N/2+1

#discovery.zen.minimum_master_nodes: 1

discovery ping的超时时间,拥塞网络,网络状态不佳的情况下设置高一点

#discovery.zen.ping.timeout: 3s

注意,分布式系统整个集群节点个数N要为奇数个!!

如何避免ElasticSearch发生脑裂(brain split):http://blog.trifork.com/2013/10/24/how-to-avoid-the-split-brain-problem-in-elasticsearch/

即使集群节点个数为奇数,minimum_master_nodes为整个集群节点个数一半加1,也难以避免脑裂的发生,详情看讨论:https://github.com/elastic/elasticsearch/issues/2488

四、常用查询

curl -X<REST Verb> <Node>:<Port>/<Index>/<Type>/<ID>

Index info:

curl -XGET 'localhost:9200'
curl -XGET 'localhost:9200/_stats?pretty'
curl -XGET 'localhost:9200/{index}/_stats?pretty'
curl -XGET 'localhost:9200/_cluster/health?level=indices&pretty=true'
curl -XGET 'localhost:9200/{index}?pretty'
curl -XGET 'localhost:9200/_cat/indices?v'
curl -XGET 'localhost:9200/{index}/_mapping/{type}?pretty'

Mapping info:
curl -XGET 'localhost:9200/subscriber/_mapping/subscriber?pretty'

Index search:
curl -XGET 'localhost:9200/subscriber/subscriber/_search?pretty'

Search by ID:
curl -XGET 'localhost:9200/subscriber/subscriber/5000?pretty'

Search by field:
curl -XGET 'localhost:9200/subscriber/subscriber/_search?q=ipAddress:63.141.15.45&&pretty'

Delete index:
curl -XDELETE 'localhost:9200/subscriber?pretty'

Delete document by ID:
curl -XDELETE 'localhost:9200/subscriber/subscriber/5000?pretty'

Delete document by query:
curl -XDELETE 'localhost:9200/subscriber/subscriber/_query?q=ipAddress:63.141.15.45&&pretty'

五、一致性(Consistent)和超时(Timeout)

翻译自官方Doc:

默认情况下,primary shard在写操作前,需要确定大多数(a quorum, or majority)的shard copies是可用的。这样是为了防止在有网络分区(network partition)的情况下把数据写到了错误的分区。

A quorum是由以下公式决定:int( (primary + number_of_replicas) / 2 ) + 1,number_of_replicas 是在index settings中指定的复制个数。

确定一致性的值有:one (只有primary shard),all (the primary and all replicas),或者是默认的quorum。

如果没有足够可用的shard copies,elasticsearch会等待直到超时,默认等待一分钟。

六、Elasticsearch插件

1、elasticsearch-head是一个elasticsearch的集群管理工具:./elasticsearch-1.7.1/bin/plugin -install mobz/elasticsearch-head

github地址:https://github.com/mobz/elasticsearch-head

2、elasticsearch-sql:使用SQL语法查询elasticsearch:./bin/plugin -u https://github.com/NLPchina/elasticsearch-sql/releases/download/1.3.5/elasticsearch-sql-1.3.5.zip --install sql

github地址:https://github.com/NLPchina/elasticsearch-sql

3、elasticsearch-bigdesk是elasticsearch的一个集群监控工具,可以通过它来查看ES集群的各种状态。

安装:./bin/plugin -install lukas-vlcek/bigdesk

访问:http://192.103.101.203:9200/_plugin/bigdesk/

github地址:https://github.com/hlstudio/bigdesk

4、elasticsearch-servicewrapper插件是ElasticSearch的服务化插件

https://github.com/elasticsearch/elasticsearch-servicewrapper

DEPRECATED: The service wrapper is deprecated and not maintained. 该项目已不再维护。

例子代码在GitHub上:https://github.com/luxiaoxun/Code4Java

参考:

https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/index.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

https://www.elastic.co/guide/en/elasticsearch/guide/current/distrib-write.html

http://stackoverflow.com/questions/10213009/solr-vs-elasticsearch

ElasticSearch的基本原理与用法相关推荐

  1. Elasticsearch 1: 基本原理和概念

    目录 1. 倒排索引 Inverted index 2. 基本概念 3. Elasticsearch索引 4. 文档 (Document) 5. 映射 6. 文档字段 6.1 数据类型 6.1.1 核 ...

  2. 第20讲:代理的基本原理和用法

    我们在做爬虫的过程中经常会遇到这样的情况,最初爬虫正常运行,正常抓取数据,一切看起来都是那么的美好,然而一杯茶的功夫可能就会出现错误,比如 403 Forbidden,这时候打开网页一看,可能会看到 ...

  3. elasticsearch安装与基础用法

    来自官网,版本为2.3 注意elasticsearch依赖jdk,2.3依赖jdk7 下载rpm包并安装 wget -c https://download.elastic.co/elasticsear ...

  4. ElasticSearch(四)之基本用法、高级查询

    为什么80%的码农都做不了架构师?>>>    回顾 搭建好了elasticsearch集群,通过elasticsearch-head插件可以监控各节点健康状态. 通过health命 ...

  5. 【Elasticsearch】 elasticsearch中 rollover 的用法

    1.概述 本章是 Elastic Stack 实战手册(早鸟版).pdf 读书笔记,记一下 加深记忆.建议直接看文档. 创作人: 杨松柏 了解 Elasticsearch 的同学应该都知道, 索引的主 ...

  6. elasticsearch里面bulk的用法

    上篇文章介绍了在es里面批量读取数据的方法mget,本篇我们来看下关于批量写入的方法bulk. bulk api可以在单个请求中一次执行多个索引或者删除操作,使用这种方式可以极大的提升索引性能. bu ...

  7. ElasticSearch: Search API 查询用法详解

    Search API ElasticSearch 为了搜索提供了一些原始的 API,主要是有两大类 URL Search URL Search 类似 http 的get请求,是将请求参数放到 URL ...

  8. elasticsearch中rollover的用法

    rollover index的作用 滚动索引一般可以与索引模板结合使用,实现按一定条件自动创建索引.设置Rollover之后,满足条件后,会自动新建索引,将索引别名转向新索引.当现有的索引太久或者太大 ...

  9. KVC基本原理和用法

    一.基本概念 KVC是Key Value Coding的缩写,意思是键值编码. 在iOS中,提供了一种方法通过使用属性的名称(也就是Key)来间接访问对象属性的方法,这个方法可以不通过getter/s ...

最新文章

  1. MySQL解压版配置
  2. 深度稳定学习:因果学习的最新进展 | 清华大学团队 CVPR 研究
  3. java webproject中logback换配置文件的路径
  4. c#中获取服务器IP,客户端IP以及Request.ServerVariables详细说明
  5. 什么是跨域?什么是CSRF?
  6. 美图秀秀 sig参数分析
  7. IXDC 2018 | 打动人心的互联网保险设计
  8. 帧同步_微信小游戏接入“熊孩子噩梦”健康系统 帧同步能力上线
  9. 通俗易懂的vuex-demo
  10. (转)oracle表分区详解
  11. Facebook 开源 Instagram 的Python 代码静态安全分析工具 Pysa
  12. 201521123004 《Java程序设计》第2周学习总结
  13. Dijkstra(堆优)模板
  14. A short theory of channel flow
  15. wpa.b.qq.com/cgi/wpa.php,营销QQ在线客服代码生成的方法(支持手机和PC)
  16. 服务器之间如何实现网络共享
  17. 弘辽科技:淘宝类目属性的型号是什么?
  18. python写一个简单的12306抢票
  19. 互联网协议-简单理解和介绍
  20. Excel使用---excel2016___一般操作(搬,侵删)

热门文章

  1. 利用存储过程得到某一指定的表与其它的表之间的外键关系SQL Server2000
  2. IDEA中如何彻底删除项目
  3. 机器学习:Python中如何使用最小二乘法
  4. HBase java 开发
  5. 关于C和C++的一点观点
  6. 基于FPGA的以太网开发
  7. centos6.3下yum安装redis
  8. 谁说女生不能搞IT?一名女程序员的奋斗史
  9. Solaris 10网络服务
  10. Roger Ver:BCH也可成为价值储备