elasticsearch原理是什么?该如何使用?

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最最强悍的功能就是为每个字段提供了倒排索引,当查询的时候都不用担心没有索引可以利用,那什么是倒排索引?举个简单例子:

elasticsearch原理

每一行是一个document(文档),每个document都有一个文档ID。那么给这些文档建立的倒排索引就是:

elasticsearch原理

可以看到,倒排索引是针对每个字段的,每个字段都有自己的倒排索引,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架构师相关信息,就请快快关注本网站吧。

推荐阅读:

elasticsearch集群安装搭建及部署该怎么配置?

elasticsearch面试题及答案详解,java常见面试题