Elasticsearch是目前最热门的搜索引擎之一,小伙伴们知道它的原理和用法是什么样的吗?今天我们就来聊聊它的原理及基本用法有哪些吧。
一、es原理简介
我们知道,Apache Lucene目前已经能够说是如今最先进、最高效的开源搜索引擎框架。但是,在基于Java的企业项目中如果想要直接集成Apache Lucene,就需要进一步将其提供的功能封装成Java API,这样的成本太高且过程复杂。所以我们就可以使用其他高效率且开源的产品,如Apache Solr和Elasticsearch。
Elasticsearch是一个建立在Apache Lucene基础上的分布式的RESTful风格的搜索和数据分析引擎,与Apache Solr相比,主要有这以下优势:
-随着数据量的增加,Solr是会逐渐变慢的,而Elasticsearch具有明显优势。
-实时搜索(在创建索引的同时进行搜索),Solr会存在IO阻塞,而Elasticsearch性能更快。
-基于以上因素,Elasticsearch更适用于新兴的实时搜索应用场景,尤其是大型互联网B2C项目。
index
Elasticsearch的索引(index)是一种用于组织数据的逻辑命名空间。Elasticsearch的索引一般有一个或多个分片(默认为5)。分片是实际上存储数据的Lucene索引,它本身为一个搜索引擎。每个分片都可以有零个或多个副本(replicas)(默认为1)。Elasticsearch索引还具有“类型”,它允许使用者在索引中对数据进行逻辑分区。Elasticsearch索引中给定“类型”中的全部文档都具有相同属性。
倒排索引
Elasticsearch最最强悍的功能就是为每个字段提供了倒排索引,当查询的时候都不用担心没有索引可以利用,那什么是倒排索引?举个简单例子:
每一行是一个document(文档),每个document都有一个文档ID。那么给这些文档建立的倒排索引就是:
可以看到,倒排索引是针对每个字段的,每个字段都有自己的倒排索引,25、32这些叫做term,[1,3]这种叫做posting list,
联合索引
如何使用联合索引查询?
-使用Skip List 数据结构,同时遍历多个term的posting list,互相skip
-使用bitset数据结构,对多个term分别求出bitset,对bitset做AN操作
二、es基本用法
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下的某个Type public 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()); } }
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; }
那么以上就是关于elasticsearch原理的所有内容了,如果还想要了解更多java架构师相关信息,就请快快关注本网站吧。
推荐阅读: