009-elasticsearch5.4.3【三】搜索概述-查询模型、分页、ES数据类型
一、概述
1、查询模型
搜索API允许用户执行搜索查询并返回与查询匹配的搜索匹配。它可以跨一个或多个索引以及跨一种或多种类型执行。可以使用查询Java API提供查询。搜索请求的主体是使用SearchSourceBuilder构建的。这是一个例子:
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.index.query.QueryBuilders.*;
SearchResponse response = client.prepareSearch("index1", "index2") .setTypes("type1", "type2") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.termQuery("multi", "test")) // Query .setPostFilter(QueryBuilders.rangeQuery("age").from(12).to(18)) // Filter .setFrom(0).setSize(60).setExplain(true) .get();
注意,所有参数都是可选的。这是您可以编写的最小的搜索调用:
// MatchAll on the whole cluster with all default options SearchResponse response = client.prepareSearch().get();
虽然Java API定义了其他搜索类型QUERY_AND_FETCH和DFS_QUERY_AND_FETCH,但这些模式是内部优化,不应由API用户明确指定。
更多API
2、分页【from+size,scroll游标】
from+size
SearchResponse response = client.prepareSearch("indexName") .setQuery(QueryBuilders.matchAllQuery()) .setFrom(10) //跳过前10个文档 .setSize(20) //获取20个文档 .execute().actionGet(); response.getHits().totalHits()可以统计当前匹配到的结果数
ES为了避免深分页,不允许使用分页(from&size)查询10000条以后的数据,因此如果要查询第10000条以后的数据,要使用ES提供的 scroll(游标) 来查询
假设取的页数较大时(深分页),如请求第20页,Elasticsearch不得不取出所有分片上的第1页到第20页的所有文档,并做排序,最终再取出from后的size条结果作爲最终的返回值
假设你有16个分片,则需要在coordinate node彙总到 shards* (from+size)条记录,即需要16*(20+10)记录后做一次全局排序
所以,当索引非常非常大(千万或亿),是无法使用from + size 做深分页的,分页越深则越容易OOM,即便不OOM,也很消耗CPU和内存资源
因此ES使用index.max_result_window:10000作爲保护措施 ,即默认 from + size 不能超过10000,虽然这个参数可以动态修改,也可以在配置文件配置,但是最好不要这麽做,应该改用ES游标来取得数据
scroll游标原理
可以把 scroll 理解爲关系型数据库里的 cursor,因此,scroll 并不适合用来做实时搜索,而更适用于后台批处理任务,比如群发
scroll 具体分爲初始化和遍历两步
初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照
在遍历时,从这个快照里取数据
也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果
游标可以增加性能的原因,是因为如果做深分页,每次搜索都必须重新排序,非常浪费,使用scroll就是一次把要用的数据都排完了,分批取出,因此比使用from+size还好
更多API
java示例
import static org.elasticsearch.index.query.QueryBuilders.*; QueryBuilder qb = termQuery("multi", "test"); SearchResponse scrollResp = client.prepareSearch(test) .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC) .setScroll(new TimeValue(60000)) .setQuery(qb) .setSize(100).get(); //max of 100 hits will be returned for each scroll //Scroll until no hits are returned do { for (SearchHit hit : scrollResp.getHits().getHits()) { //Handle the hit... } scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet(); } while(scrollResp.getHits().getHits().length != 0); // Zero hits mark the end of the scroll and the while loop.
3、多搜索
更多API
SearchRequestBuilder srb1 = client .prepareSearch().setQuery(QueryBuilders.queryStringQuery("elasticsearch")).setSize(1); SearchRequestBuilder srb2 = client .prepareSearch().setQuery(QueryBuilders.matchQuery("name", "kimchy")).setSize(1); MultiSearchResponse sr = client.prepareMultiSearch() .add(srb1) .add(srb2) .get(); // You will get all individual responses from MultiSearchResponse#getResponses() long nbHits = 0; for (MultiSearchResponse.Item item : sr.getResponses()) { SearchResponse response = item.getResponse(); nbHits += response.getHits().getTotalHits(); }
4、提前终止
在达到每个分片收集的最大文档数查询执行将提前终止时,如果设置,您将能够通过在SearchResponse onject中请求isTerminatedEarly()来检查操作是否提前终止:
SearchResponse sr = client.prepareSearch(INDEX) .setTerminateAfter(1000) .get(); if (sr.isTerminatedEarly()) { // We finished early }
5、查询模板
参看地址
二、ES数据类型
2.1、映射(Mapping)
相当于数据表的表结构。ElasticSearch中的映射(Mapping)用来定义一个文档,可以定义所包含的字段以及字段的类型、分词器及属性等等。
映射可以分为动态映射和静态映射。
动态映射 (dynamic mapping):在关系数据库中,需要事先创建数据库,然后在该数据库实例下创建数据表,然后才能在该数据表中插入数据。而ElasticSearch中不需要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。
静态映射 :在ElasticSearch中也可以事先定义好映射,包含文档的各个字段及其类型等,这种方式称之为静态映射。
2.2、数据类型
一级分类 | 二级分类 | 具体类型 | 说明 |
核心类型 | 字符串类型 | string,text,keyword |
1、string是2.x版本的,从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代 没有string类型了,全部用text,而且text的,自动加了keyword属性,如果精确查找,后面直接加keyword就ok,例如: name.keyword='中国' |
整数类型 | integer,long,short,byte | 在满足需求的情况下,尽可能选择范围小的数据类型。比如,某个字段的取值最大值不会超过100,那么选择byte类型即可。字段的长度越短,索引和搜索的效率越高。 | |
浮点类型 | double,float,half_float,scaled_float | 对于float、half_float和scaled_float,-0.0和+0.0是不同的值,使用term查询查找-0.0不会匹配+0.0,同样range查询中上边界是-0.0不会匹配+0.0,下边界是+0.0不会匹配-0.0。 其中scaled_float,比如价格只需要精确到分,price为57.34的字段缩放因子为100,存起来就是5734 优先考虑使用带缩放因子的scaled_float浮点类型。 |
|
逻辑类型 | boolean | 逻辑类型(布尔类型)可以接受true/false/”true”/”false”值 | |
日期类型 | date | 日期类型表示格式可以是以下几种: (1)日期格式的字符串,比如 “2018-01-13” 或 “2018-01-13 12:10:30” (2)long类型的毫秒数( milliseconds-since-the-epoch,epoch就是指UNIX诞生的UTC时间1970年1月1日0时0分0秒) (3)integer的秒数(seconds-since-the-epoch) ElasticSearch 内部会将日期数据转换为UTC,并存储为milliseconds-since-the-epoch的long型整数。 |
|
范围类型 | range | ||
二进制类型 | binary |
二进制字段是指用base64来表示索引中存储的二进制数据,可用来存储二进制形式的数据,例如图像。 默认情况下,该类型的字段只存储不索引。二进制类型只支持index_name属性。 |
|
复合类型 | 数组类型 | array | 在ElasticSearch中,没有专门的数组(Array)数据类型,但是,在默认情况下,任意一个字段都可以包含0或多个值,这意味着每个字段默认都是数组类型,只不过,数组类型的各个元素值的数据类型必须相同。在ElasticSearch中,数组是开箱即用的(out
of box),不需要进行任何配置,就可以直接使用。 在同一个数组中,数组元素的数据类型是相同的,ElasticSearch不支持元素为多个数据类型:[ 10, “some string” ],常用的数组类型是: (1)字符数组: [ “one”, “two” ] (2)整数数组: productid:[ 1, 2 ] (3)对象(文档)数组: “user”:[ { “name”: “Mary”, “age”: 12 }, { “name”: “John”, “age”: 10 }],ElasticSearch内部把对象数组展开为 {“user.name”: [“Mary”, “John”], “user.age”: [12,10]} |
对象类型 | object | JSON天生具有层级关系,文档会包含嵌套的对象 | |
嵌套类型 | nested | 用于JSON数组 | |
地理类型 | 地理坐标类型 | geo_point | 用于经纬度坐标; |
地理地图 | geo_shape | 用于类似于多边形的复杂形状 | |
特殊类型 | IP类型 | ip | ip类型的字段用于存储IPv4或者IPv6的地址 |
范围类型 | completion | 提供自动补全建议 | |
令牌计数类型 | token_count | 用于统计做了标记的字段的index数目,该值会一直增加,不会因为过滤条件而减少。 | |
附件类型 | attachment | 采用 mapper-attachments 插件,可支持 attachments 索引,例如 Microsoft Office 格式,Open Document 格式,ePub, HTML 等。 | |
抽取类型 | percolator |