ElasticSearch操作笔记

来源:互联网 发布:工作流程梳理软件 编辑:程序博客网 时间:2024/05/22 08:07

ElasticSearch

一、概述

1、ElasticSearch

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。

但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。

Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它:

分布式的实时文件存储,每个字段都被索引并可被搜索;

分布式的实时分析搜索引擎;

可以扩展到上百台服务器,处理PB级结构化或非结构化数据。

而且,所有的这些功能被集成到一个服务里面,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。

上手Elasticsearch非常容易。它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。

Elasticsearch在Apache 2 license下许可使用,可以免费下载、使用和修改。随着你对Elasticsearch的理解加深,你可以根据不同的问题领域定制Elasticsearch的高级特性,这一切都是可配置的,并且配置非常灵活。

 

2、Lucene

十分钟了解Lucene:

http://blog.csdn.net/exceptional_derek/article/details/21179509

3、同类应用

1、Solr

Solr是用Java编写、运行在Servlet容器(如 Apache Tomcat 或Jetty)的一个独立的全文搜索服务器。 Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具有类似REST的HTTP/XML和JSON的API。Solr强大的外部配置功能使得无需进行Java编码,便可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制。

因为2010年 Apache Lucene 和 Apache Solr 项目合并,两个项目是由同一个Apache软件基金会开发团队制作实现的。提到技术或产品时,Lucene/Solr或Solr/Lucene是一样的。

 

1-1、对比

ES:

优点:

1. Elasticsearch是分布式的。不需要其他组件,分发是实时的,被叫做”Push replication”。

2. Elasticsearch 完全支持 Apache Lucene 的接近实时的搜索。

3. 处理多租户(multitenancy)不需要特殊配置,而Solr则需要更多的高级设置。

4. Elasticsearch 采用 Gateway 的概念,使得完备份更加简单。

5. 各节点组成对等的网络结构,某些节点出现故障时会自动分配其他节点代替其进行工作。

缺点:

1. 只有一名开发者(当前Elasticsearch GitHub组织已经不只如此,已经有了相当活跃的维护者)

2. 还不够自动(不适合当前新的Index Warmup API)

 

Solr:

优点:

1. Solr有一个更大、更成熟的用户、开发和贡献者社区。

2. 支持添加多种格式的索引,如:HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。

3. Solr比较成熟、稳定。

4. 不考虑建索引的同时进行搜索,速度更快。

缺点:

1. 建立索引时,搜索效率下降,实时索引搜索效率不高。

 

 

 

 

ESSolr:http://www.cnblogs.com/chowmin/articles/4629220.html

 

二、使用场景

分布式的全文检索。近实时搜索。

一些国外优秀的elasticsearch使用案例

Github

“Github使用Elasticsearch搜索20TB的数据,包括13亿的文件和1300亿行的代码”

这个不用介绍了吧,码农们都懂的,Github在2013年1月升级了他们的代码搜索,由solr转为elasticsearch,目前集群规模为26个索引存储节点和8个客户端节点(负责处理搜索请求),详情请看官方博客
https://github.com/blog/1381-a-whole-new-code-search

Foursquare
”实时搜索5千万地点信息?Foursquare每天都用Elasticsearch做这样的事“

Foursquare是一家基于用户地理位置信息的手机服务网站,并鼓励手机用户同他人分享自己当前所在地理位置等信息。与其他老式网站不同,Foursquare用户界面主要针对手机而设计,以方便手机用户使用。

SoundCloud
“SoundCloud使用Elasticsearch来为1.8亿用户提供即时精准的音乐搜索服务”

SoundCloud是一家德国网站,提供音乐分享社区服务,成长很快,Alexa世界排名已达第236位。你可以在线录制或上传任何声音到SoundCloud与大家分享,可在线上传也可以通过软件客户端来上传音乐文件,没有文件大小限制,但免费版限制上传音频总长不可超过2个小时播放时长,每首歌曲限最多100次下载。SoundCloud允许音乐通过Flash播放器方式嵌入到网页中。

Fog Creek
“Elasticsearch使Fog Creek可以在400亿行代码中进行一个月3千万次的查询“

StumbleUpon
”Elasticsearch是StumbleUpon的关键部件,它每天为社区提供百万次的推荐服务“StumbleUpon是个能发现你喜欢的网页的网站,进去时先注册,注册完就选择你感兴趣的东西,它会自动帮你推荐一些网页,如果你喜欢这个网页就点喜欢按钮,按 stumble按钮就会推荐下一个网页。
目前其数据量达到 25亿,基本数据存储在HBase中,并用 elasticsearch建立索引,elasticsearch 在其中除了用在搜索功能还有在推荐和统计功能。之前他们是使用solr作为搜索,由于solr满足不了他们的业务增长需要而替换为 elasticsearch。

Mozilla
Mozilla公司以火狐著名,它目前使用 WarOnOrange 这个项目来进行单元或功能测试,测试的结果以 json的方式索引到elasticsearch中,开发人员可以非常方便的查找 bug。
Socorro是Mozilla 公司的程序崩溃报告系统,一有错误信息就插入到 Hbase和Postgres 中,然后从 Hbase中读取数据索引到elasticsearch中,方便查找。

Sony
Sony公司使用elasticsearch 作为信息搜索引擎

Infochimps
Infochimps,我们已经索引了25亿文档,总共占用 4TB的空间”。
Infochimps是一家位于德克萨斯州奥斯丁的创业公司,为大数据平台提供商。它主要提供基于hadoop的大数据处理方案。

 

三、名词概念

1、Cluster(集群)

一个集群包含一个或多个分配了相同的集群名称的节点。每个集群都有一个主节点,是集群自动选择产生,并且可以决定如果当前主节点失败,哪些节点有资格被选为主节点

 

2、Node(节点)

节点是属于elasticsearch群集的运行实例。测试的时候,在一台服务器可以启动多个节点,但通常情况下应该在一台服务器运行一个节点。

 

3、Index(索引)

既可以是名词也可以是动词,名词:在ES中索引相当于一个数据库。动词:建立索引,将文档(json格式)存到存到ES中。

4、Type(类型)

TypeIndex下的一个子集,相当于数据库下的一张表。一个Index下可以有多个Type

5、Document(文档)

Document相当于表中的一条记录。ES中文档只支持json格式。
6、Mapping(映射)

一个类型(相当于一张表)对应一个映射,映射中定义文档某个字段的数据类型(:String,Integer,Date,Geo-point地理坐标)

7、Settings(设置)

一个Index对应一个Settings,包含了该Index的相关配置信息,如副本数,分片数。

8、Shards(分片)

创建索引的时候,可以在该索引的Settings中设置该索引的分片数量(默认是5),一个索引在磁盘上对应一个文件夹,一个分片是对应该文件夹下的一个子文件夹。

9、Replications(副本)

一个索引可以指定多个副本(默认是1)。

10、Gateway(时间机器)

gateway 代表 elasticsearch索引的持久化存储方式,elasticsearch默认是先把索引存放到内存中去,当内存满了的时候再持久化到硬盘里。

当这个 elasticsearch 集群关闭或者再次重新启动时就会从 gateway 中读取索引数据。

elasticsearch 支持多种类型的 gateway,有本地文件系统(默认),分布式文件系统,HadoopHDFSamazons3云存储服务。

 

四、实践操作

1、安装配置

1-1、下载软件包

https://www.elastic.co/products/elasticsearch

Windows下下载zip包即可,下载完后解压到任意路径。

1-2、各个目录解释

 

 

1-3、配置文件解释

主要的配置文件为conf/elasticsearch.yml

cluster.name: application(集群名称,不配置默认是elasticsearch)

Node.name:node-1(当前节点名词,不配置随机分配)

#node.master: true(是否有资格成为master主节点)

#node.data: true(是否是data节点,存数据)

network.host: 192.168.2.111(当前节点的Ip地址)

discovery.zen.ping.unicast.hosts:["192.168.2.111:9300","192.168.2.115:9300"] (集群中节点的ip地址,所有节点的集群名称要一致)

transport.tcp.port: 9300

#设置节点间交互的tcp端口,默认是9300

 

transport.tcp.compress: true

#设置是否压缩tcp传输时的数据,默认为false,不压缩。

 

http.port: 9200

#设置对外服务的http端口,默认为9200

1-4、启动

(1)运行bin/elasticsearch.bat启动

(2)安装为windows服务,/bin/elasticsearch-service install(start,stop,remove,manager)

(3)图形界面启动:elasticsearch-service manager

 启动完成后在浏览器段查看:http://192.168.2.117:9200/

 

 

 

2、Restful接口操作es

1http://192.168.2.111:9200/_cat/nodes?v ------------------查看所有节点

2http://192.168.2.111:9200/_cat/indices?v ---------------查看所有索引

3http://192.168.2.111:9200/_cat/health?v -------------查看集群相关信息

4http://192.168.2.111:9200/_cluster/health----------查看集群健康指标

 

status字段提供的值反应了集群整体的健康程度。它的值的意义如下:

green:所有的主分片(Primary Shard)和副本分片(Replica Shard)都处于活动状态

yellow:所有的主分片都处于活动状态,但是并不是所有的副本分片都处于活跃状态

red:不是所有的主分片都处于活动状态

具体api参考官方文档:

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

 

3、javaApi操作ES

javaAPI官方文档:

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

3-1、搭建maven工程,引入jar

新建maven工程,在pom文件中添加依赖。

 

3-2、创建索引

//创建setting,setting中可以对对一些配置信息进行设置,如分片数,副本数

Settings settings =Settings.builder()

.put("cluster.name", CLUSTER_NAME)

.put("client.transport.sniff",true)//传输端口嗅探,探集群中的节点,自动添加到集合中

.put("client.transport.ignore_cluster_name",true)//Set to true to ignore cluster name validation of connected nodes

.put("client.transport.ping_timeout",5)//The time to wait for a ping response from a node ,Defaults to 5s

.put("client.transport.nodes_sampler_interval",5)//How often to sample / ping the nodes listed and connected,Defaults to 5s

.build();

//创建客户端

TransportClient client =new PreBuiltTransportClient(Settings.EMPTY);

 

//创建索引

 

 IndicesAdminClient indicesAdminClient =client.admin().indices();

       CreateIndexResponse response =indicesAdminClient.prepareCreate("index_name").get();//创建索引,指定索引名称

       boolean flag =response.isAcknowledged();

 

 

3-3、创建索引并设置setting和mapping

//创建setting

Settings settings = Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 1).build();

//创建mapping(指定某些字段的数据类型,以及是否建立索引是否存储)

 XContentBuilder mappingBuilder  = XContentFactory.jsonBuilder()

.startObject()

.startObject("properties")

.startObject("name").field("type","string").field("store","yes").endObject()

.startObject("sex").field("type","string").field("store","yes").endObject()

.startObject("college").field("type","string").field("store","yes").endObject()

.startObject("age").field("type","integer").field("store","yes").endObject()

.startObject("school").field("type","string").field("store","yes").field("index","not_analyzed").endObject()                             

 .endObject()

.endObject();

 

CreateIndexResponse response =indicesAdminClient.prepareCreate("my_index")

                .setSettings(settings)

                .addMapping("my_type",mappingBuilder.string())//第一个参数是类型,Mapping对应的类型(类型相于表)

                .get();

 

 

3-4、删除索引

IndicesAdminClient indicesAdminClient =client.admin().indices();

DeleteIndexResponse response = =indicesAdminClient.prepareDelete("index_name").execute().actionGet();

//指定要删除的索引的名称

3-5、关闭索引

关闭不使用的索引,进而释放节点和集群的资源,如cpu时钟周期和内存

 IndicesAdminClient indicesAdminClient =client.admin().indices();

        CloseIndexResponse response =indicesAdminClient.prepareClose("index_name").get();

 

3-6、打开索引

 IndicesAdminClient indicesAdminClient =client.admin().indices();

        OpenIndexResponse response =indicesAdminClient.prepareOpen("index_name").get();

 

3-7、添加或是更新mapping

IndicesAdminClient indicesAdminClient =client.admin().indices();

        

        PutMappingResponse response =indicesAdminClient.preparePutMapping("index_name").setType("my_type").setSource(mappingBuilder).get();//mappingBuilder的创建参考3-3

 

3-8、为索引创建别名

IndicesAdminClient indicesAdminClient =client.admin().indices();

       IndicesAliasesResponse response =indicesAdminClient.prepareAliases().addAlias(indexName,alias).get();

3-9、判断别名是否存在

IndicesAdminClient indicesAdminClient =client.admin().indices();

       AliasesExistResponse response =indicesAdminClient.prepareAliasesExist(aliases).get();//传入的可以是字符串数组

       return response.isExists();

3-10、更新setting

 IndicesAdminClient indicesAdminClient =client.admin().indices();

       UpdateSettingsResponse response =indicesAdminClient.prepareUpdateSettings(index).setSettings(settings).get();

       return response.isAcknowledged();

3-11、添加文档(Document)

/**

 * 第一个参数 ---索引名称

 * 第二个参数---type名称

 * 第三个参数---document的id

 */

 IndexRequestBuilder indexRequestBuilder =client.prepareIndex("index1","type1", "id1");

 IndexResponse response = indexRequestBuilder.setSource(JSON_SOURCE)

         .get();

//JSON_OURCE就是文档内容,必须是json格式,如果索引和类型不存在的话,会自动创建        

 

3-12、根据id获取文档

GetRequestBuilder prepareGet = client.prepareGet("index1", "type1", "id1");

GetResponse response = prepareGet.setOperationThreaded(false).get();

String id = response.getId();

String index = response.getIndex();

String type = response.getType();

 // Version (if it's the first time you index this document, you will get: 1)

        long _version =response.getVersion();

 

System.out.println(index+"\t"+type+"\t"+id+"\t"+_version);

Map<String, Object> source = response.getSource();//获取文档,添加的文档内容实际是在_source字段下。

 

3-13、根据id删除

DeleteRequestBuilder deleteBuilder =client.prepareDelete();

deleteBuilder.setIndex("index");

deleteBuilder.setType("type");

deleteBuilder.setId("1");

DeleteResponse response = deleteBuilder.get();

3-14、条件删除(查询删除)

BulkIndexByScrollResponse response =

    DeleteByQueryAction.INSTANCE.newRequestBuilder(client)

        .filter(QueryBuilders.matchQuery("message","新数据"))

//message字段中包含”新数据”内容的文档

        .source("my_name2")    //索引名称                              

        .get();                                             

 

long deleted =response.getDeleted();

3-15、更新文档

UpdateRequest updateRequest = new UpdateRequest();

updateRequest.index("index1");

updateRequest.type("type1");

updateRequest.id("id1");

//更新文档内容

updateRequest.doc(UPDATE_JSON_SOURCE);

//新的文档如果字段比原来的少,原来多余的字段也不会删除

//更新字段

//updateRequest.script(new Script("ctx._source.message = \"更新的数据\""));

//client.update(updateRequest).get();

3-16、添加字段

//接更新文档,将新的字段加进去

UpdateRequest updateRequest = new UpdateRequest("index1","type1", "id1")

        .doc(ADD_FIELD_JSON_SOURCE);

                  

client.update(updateRequest).get();

 

3-17、获取多篇文档

MultiGetResponse multiGetItemResponses =client.prepareMultiGet()

    .add("my_name", "my_type", "my_id")   //索引名,类型名,文档id        

    .add("my_name", "my_type", "my_id", "my_id2", "my_id3") //指定多个id

    .add("another", "type", "foo")    //其他索引库      

    .get();

 

for (MultiGetItemResponseitemResponse : multiGetItemResponses) {

    GetResponse response = itemResponse.getResponse();

    if (response.isExists()) {                      

        String json = response.getSourceAsString();

        System.out.println(json);

    }

}

 

3-18、插入多条数据

BulkRequestBuilder bulkRequest = client.prepareBulk();

//第一篇文档

bulkRequest.add(client.prepareIndex("my_name","my_type", "my_id")

        .setSource(JSON_SOURCE).request()

        );

//第二篇文档

 

bulkRequest.add(client.prepareIndex("my_name","my_type", "my_id2")

        .setSource(UPDATE_JSON_SOURCE).request()

        );

BulkResponse bulkResponse = bulkRequest.get();

if (bulkResponse.hasFailures()) {

System.out.println("插入失败");

}

3-19、经纬度

ESMapping用于指定字段的数据类型,该数据类型可以是String,Integer,Date等,还有两种比较特殊分别是geo_pointgeo_shape.

1、geo_point:该数据类型用于说明该字段的值是一个经纬度坐标。

支持的数据格式有四种(纬度在前,经度在后):

1){     "lat": 41.12,

    "lon": -71.34

   }//对象

2"41.12,-71.34" ----------第二种//字符

3"drm3btev3e86"  -----------(geohash)

4[ -71.34, 41.12 ] -----数组

也就是说如果该字段被指定为geo_point类型,那么对应的json文档该字段的值只能是这四种格式的数据。

2、geo_point案例

1)创建索引并设置Mapping

 String mapping = "{"+

            "\"properties\": {"+

                "\"pin\": {"+

                   "\"properties\": {"+

                        "\"location\": {"+

                            "\"type\": \"geo_point\"}"+//指定pin.location属性是geo_point类型(有两种:geo_point,geo_shape)         

                       "}"+

                  "},"+

                  "\"name\": {"+

                   "\"type\": \"string\"},"+

                  "\"cityId\": {"+

                   "\"type\": \"string\"}"+

                "}"+

           "}";

//Mapping中可以看出,要添加的文档有三个属性,cityId,name,pin,其中pin是一个对象,该对象也有一个属性为location,locationgeo_point类型,也就是说,文档中该字段的数据格式必须是指定的四种格式之一

   IndicesAdminClient indicesAdminClient =client.admin().indices();

        CreateIndexResponse response =indicesAdminClient.prepareCreate(SPATIAL_INDEX)               

                .addMapping(SPATIAL_TYPE,mapping)//第一个参数是type(一个type对应一个mapping,添加文档的时候类型必须是这里指定的类型,不然添加失败

                .get();

 

2)添加文档

文档格式:

{"cityId":187,"name":"武汉","pin":{"location":{"lat":30.52,"lon":114.31}}}

 

BulkRequestBuilder bulkRequest = client.prepareBulk();

//天添加多篇文档

List<CityGeoInfo> cities = GeoUtils.getCityGeoInfoFromFile();

for(CityGeoInfo info : cities){

String json = JsonUtils.objectToJson(info);

bulkRequest.add(client.prepareIndex(SPATIAL_INDEX,SPATIAL_TYPE, info.getCityId()+"")

        .setSource(json));

System.out.println(json);

 

}

BulkResponse bulkResponse = bulkRequest.get();

3)查询,根据中心点查询方圆100公里的城市

 SearchRequestBuilder srb = client.prepareSearch(SPATIAL_INDEX).setTypes(SPATIAL_TYPE);

 

 QueryBuilder builder = new GeoDistanceQueryBuilder("pin.location")  //坐标字段

                .point(lat,lon)//注意纬度在前,经度在后  

                .distance(100D, DistanceUnit.KILOMETERS);

  

        srb.setQuery(builder);

       GeoDistanceSortBuilder sort =new GeoDistanceSortBuilder("pin.location",new GeoPoint(lat,lon));

       sort.order(SortOrder.ASC);

       srb.addSort(sort);

        SearchResponse searchResponse =srb.execute().actionGet();

        SearchHits hits = searchResponse.getHits();  

        SearchHit[] searchHists = hits.getHits();  

        System.out.println("结果共有:(" +hits.getTotalHits() + "条):");

        for(SearchHithit : searchHists){

         String name = (String) hit.getSource().get("name");

          //System.out.println("名称:"+name);

         // 获取距离值,并保留三位小数点  

            BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);

            Map<String, Object> hitMap =hit.getSource();  

            // 在创建MAPPING的时候,属性名的不可为geoDistance。  

            hitMap.put("geoDistance",geoDis.setScale(3, BigDecimal.ROUND_HALF_DOWN));  

            System.out.println("名称:"+name +"距离:" + hit.getSource().get("geoDistance") + DistanceUnit.KILOMETERS.toString());  

            

        }

2、geo_shape:该数据类型用于说明该字段的值是一个由多个经纬度坐标围成的一个形状。

案例:

1)创建索引,设置Mapping

 String mapping = "{"+

            "\"properties\": {"+

                "\"pin\": {"+

                   "\"properties\": {"+

                        "\"location\": {"+

                            "\"type\": \"geo_shape\"}"+//指定pin.shape属性是geo_shape类型(有两种:geo_point,geo_shape)         

                       "}"+

                  "},"+

                  "\"name\": {"+

                   "\"type\": \"string\"},"+

                  "\"id\": {"+

                   "\"type\": \"string\"}"+

                "}"+

           "}";

 IndicesAdminClient indicesAdminClient =client.admin().indices();

 CreateIndexResponse response = indicesAdminClient.prepareCreate(SPATIAL_INDEX)  //索引名称             

         .addMapping(SPATIAL_TYPE,mapping)//第一个参数是type,添加文档的时候类型必须是这里指定的类型,不然添加失败

         .get();

2)构建一个形状,然后添加到索引库

文档格式:

{"id":"polygon_1","name":"多边形","pin":{

    "location" : {

        "type" : "polygon",

        "coordinates" : [

            [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]

        ]

    }

}}

double[][][] coordinates= {

{ {100.0, 0.0},//经度,纬度

{101.0, 0.0},

{102.0, 2.0},

{100.0, 1.0},

{100.0, 0.0}

}

};

ShapeLocation location = new ShapeLocation(SHAPE_TYPE,coordinates);

Pin pin = new Pin(location);

com.deng.elasticsearch.entity.shape.SpatialShape spatialShape =

new com.deng.elasticsearch.entity.shape.SpatialShape(SHAPE_ID,SHAPE_NAME,pin);

String source = JSON.toJSONString(spatialShape);

System.out.println(source);

/**

 * 第一个参数 ---索引名称

 * 第二个参数---type名称

 * 第三个参数---document的id

 */

 IndexRequestBuilder indexRequestBuilder =

 client.prepareIndex(SPATIAL_INDEX,SPATIAL_TYPE, "1");

     IndexResponse response =indexRequestBuilder

      .setSource(source)

          .get();         

 

 

3)用形状来检索存到索引库中的形状

//构造一个形状

 List<Coordinate> points = new ArrayList<Coordinate>();

 points.add(new Coordinate(90.0,-1));

 points.add(new Coordinate(110.0,-2));

 points.add(new Coordinate(112.0,3));

 points.add(new Coordinate(95,2));

 points.add(new Coordinate(90.0,-1));

 

 SearchRequestBuilder srb = client.prepareSearch(SPATIAL_INDEX).setTypes(SPATIAL_TYPE);

 ShapeBuilder polygonShape = ShapeBuilders.newPolygon(points);

 

//查询条件

 QueryBuilder builder = new GeoShapeQueryBuilder("pin.location",polygonShape).relation(ShapeRelation.INTERSECTS);//只要检索的形状和被检索的形状有交集,就满足检索条件,该形状会被检索出来

        srb.setQuery(builder);

        SearchResponse searchResponse =srb.execute().actionGet();

        SearchHits hits = searchResponse.getHits();  

        SearchHit[] searchHists = hits.getHits();  

        System.out.println("结果共有:(" +hits.getTotalHits() + "条):");

        for(SearchHithit : searchHists){

         String name = (String) hit.getSource().get("name");

          System.out.println("名称:"+name);                      

        }

3-20、查询

//QueryBuilders构建查询条件(这里只列举了一个termQuery

//Scroll用于设置分页,setSize用于设置每页大小

QueryBuilder qb = QueryBuilders.termQuery("name","18");

//第一次搜索,获取第一页数据和总记录数和scrollId

SearchResponse scrollResp = client.prepareSearch(INDEX_NAME)

.setTypes(TYPE)

.setQuery(qb)

        .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC)

        .setScroll(new TimeValue(60000))//scroll搜索会把搜索结果缓存起来,这里设置缓存的时间

        .setSize(size).get(); //max of 100 hits will be returned for each scroll

 

 

五、进阶优化

Es的很多配置要么会根据当前机器动态设置,要么有的配置设置好了比较合适的默认值,需要用户自行设置的配资项比较少。性能优化可以从以下几个方面考虑:

1)bulk请求时,每个请求大小建议5-15MB

2)写入数据时,确保bulk请求时轮询访问所有节点。

3)磁盘优化,使用SSD,使用多个磁盘个ElasticSearch访问,通过path.data中添加

4)不要使用远程存储

5)段合并

段合并:每个分片和分片副本实际上是Apache Lucene的索引,由多个段(至少一个段)组成。读者应该还记得,段数据都是一次写入,多次读取,当然保存删除文档的文件除外,该文件可以随机改变。经过一段时间,当条件满足时,多个小的段中的内容会被复制到一个大的段中,原来的那些小段就会丢弃,然后从硬盘上删除。这个过程称为段合并(segment merging)

段合并是很消耗计算资源和磁盘IO的操作,特别是出现比较大的段合并。 
当出现段合并的速度落后于索引写入的速度,Elasticsearch为了避免出现堆积的段数量爆发,会降低单个线程的索引写入速度,并且会在INFO的log里记录“now throttling indexing“

Elasticsearch默认比较保守,不想让搜索的性能被后台的段合并影响,默认的段合并速率限制比较低,默认是20MB/s,但如果使用的是SSD,可以考虑把这个参数设置到100-200MB/s.

PUT /_cluster/settings { "persistent" : {"indices.store.throttle.max_bytes_per_sec" :"100mb" } }

如果你只是用bulk导入数据而不关注查询性能,可以关闭合并的阈值.

PUT /_cluster/settings { "transient" : {"indices.store.throttle.type" :"none" } }

6)刷新率

索引数据的提交也不能保证数据是搜索可见的。Lucene工具包使用一个名为Searcher的抽象类来读取索引。索引提交操作完成后,Searcher对象需要重新打开才能加载到新创建的索引段。这整个过程称为更新。出于性能的考虑,ElasticSearch会将推迟开销巨大的更新操作,默认情况下,单个文档的添加并不会触发搜索器的更新,Searcher对象会每秒更新一次(刷新率)。这个频率已经比较高了,但是在一些应用程序中,需要更频繁的更新。对面这个需求,我们可以考虑使用其它的解决方案或者再次核实我们是否真的需要这样做。如果确实需要,那么可以使用ElasticSearch API强制更新

如果不需要实时精确的查询结果,可以把每个索引index.refresh_interval设置为30s,如果在导入大量的数据,可以把这个值先设置为-1,完成数据导入之后在设置回来

curl -XPUT localhost:9200/test/_settings -d '{

    "index" : {

        "refresh_interval" : "5m"

    }

}'

上面的命令将使Searcher每5秒钟自动更新一次。请记住在更新两个时间点之间添加到索引的数据对查询是不可见的。

7)写数据时先把副本数设置为0

如果在用bulk导入大量的数据,可以考虑不要副本。index.number_of_replicas: 0。有副本存在的时候,导入数据需要同步到副本,并且副本也要完成分析,索引和段合并的操作,影响导入性能。可以不设置副本导入数据然后在恢复副本。

8)禁用虚拟内存

9)增大内存,官方建议分配最大内存的一半给es,在配置文件jvm.options文件中配置,默认是2g

10)索引缓存

indices.memory.index_buffer_size 默认是jvm10%确保他足够处理至多512MB的索引

 

 

1 0
原创粉丝点击