ElasticSearch业务逻辑案例
ElasticSearch业务逻辑案例
一.业务难题
我们有一个索引: myindex/mytype
(为了方便,我们下文以a/b
表示)
索引类型中的一个字段group
之前是a.b.c
(历史遗留问题), 我们查询是这样的:
POST 127.0.0.1:9200/a/b/_search
{
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"regexp": {
"group": "a.b.*"
}
}
]
}
}
}
},
"highlight": {
"fields": {
"*": {}
}
},
"_source": {
"include": [
"group"
]
}
}
正则查询比较慢! 我们希望能够兼容之前查询, 并且优化它.
二.分析
我们分析了三种数据类型的区别, 在ES5中, 出现了两种数据类型text
和keyword
ES5中的"text"相当于ES2中的"string", 而"keyword"相当于"text", 但分析器不进行分词索引, 等价于index设置为not_analyze
index这个参数可以控制字段应该怎样建索引,怎样查询。它有以下三个可用值:
1· no
: 不把此字段添加到索引中,也就是不建索引,此字段不可查询
2· not_analyze
:将字段的原始值放入索引中,作为一个独立的term,它是除string字段以外的所有字段的默认值。 ES5.0 type keyword使用这种
3· analyzed
:string字段的默认值,会先进行分析后,再把分析的term结果存入索引中。
因为索引一旦建立, 就不能修改字段属性了, 所以我们要新建索引, 并且找时间进行迁移.
其他优化:
因为ES可以动态加字段(可能手误), 我们不希望为这些字段进行索引, 所以设置"dynamic": false
, 表示虽然保存这个数据但是不自动填加进mapping. 如果设置为strict, 表示如果检测到新字段, 马上报错. 同时, 对于某些字段, 我们进行mapping, 但是不希望检索, 所以index设置为no.
如果一个字段被设置为keyword
, 然后传入值的时候传入['a','b']
时, 这时这个字段为多值字段, 这是自动封箱的, 对于所有ES字段, 底层都是一个列表(分词).
补充(参见http://www.cnblogs.com/ljhdo/p/4904430.html:
ES支持的数据:
long:64位存储
integer:32位存储
short:16位存储
byte:8位存储
double:64位双精度存储
float:32位单精度存储
初次之外还可以支持其他复杂的类型
- 数组类型:没有明显的字段类型设置,任何一个字段的值,都可以被添加0个到多个,要求,他们的类型必须一致,当类型一直含有多个值存储到ES中会自动转化成数组类型
- 对象类型:存储类似json具有层级的数据
- 嵌套类型:支持数组类型的对象Array[Object],可层层嵌套
对于数组类型的数据,是一个数组元素做一个数据单元,如果是分词的话也只是会依一个数组元素作为词源进行分词。不会是所有的数组元素整合到一起。在查询的时候如果数组里面的元素有一个能够命中那么将视为命中,被召回。
在ElasticSearch内部,嵌套的文档(Nested Documents)被索引为很多独立的隐藏文档(separate documents),这些隐藏文档只能通过嵌套查询(Nested Query)访问。每一个嵌套的文档都是嵌套字段(文档数组)的一个元素。嵌套文档的内部字段之间的关联被ElasticSearch引擎保留,而嵌套文档之间是相互独立的。在该例中,ElasticSearch引起保留Alice和White之间的关联,而John和White之间是没有任何关联的。
默认情况下,每个索引最多创建50个嵌套文档,可以通过索引设置选项:index.mapping.nested_fields.limit
修改默认的限制。
我们区分了object
, nested
, text/keyword
的差别. nested
主要针对对象数组(保留对象关联关系), "text/keyword"通过设置子属性可以实现对象数组(但关联关系丢失).
三.解决/测试
我们进行索引重建并且进行测试:
3.1.删除索引
DELETE /a
3.2新建索引
PUT /a
{
"mappings": {
"jobs": {
"include_in_all": false,
"dynamic": false,
"properties": {
"group": {
"type": "keyword"
},
"test1": {
"properties": {
"first": {
"type": "keyword"
},
"last": {
"type": "keyword"
}
}
},
"test2": {
"type": "nested",
"properties": {
"first": {
"type": "keyword"
},
"last": {
"type": "keyword"
}
}
},
"run_detail": {
"type": "text",
"index": "no"
}
}
}
}
}
3.3.插入数据测试
PUT /a/b/1
{
"group": [
"a",
"b"
],
"test1": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
],
"test2": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
test1是没关联的对象数组, 而test2是有关联的, 对于嵌套, 查询是这样的(对象扁平化了):
POST /a/b/_search
{
"query": {
"nested": {
"path": "test2",
"query": {
"bool": {
"must": [
{
"match": {
"test2.first": "Alice"
}
},
{
"match": {
"test2.last": "White"
}
}
]
}
}
}
}
}
我们开始测试group
字段, 随机插入数据, id是自动生成的
POST /a/b
{
"group": "a.b.c.d"
}
POST /a/b
{
"group": ["a","b"]
}
测试开始:
3.4.正则查询
POST /a/b/_search
{
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"regexp": {
"group": "a.b.*"
}
}
]
}
}
}
},
"highlight": {
"fields": {
"*": {}
}
},
"_source": {
"include": [
"group"
]
}
}
这种方式比较慢, 对于group是单个值的, 那正则匹配单个值, 多个值的, 那么分别正则匹配, 有一个匹配到就返回.
3.5.terms查询
POST /a/b/_search
{
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"terms": {
"group": [
"a",
"b",
"c"
]
}
}
]
}
}
}
},
"highlight": {
"fields": {
"*": {}
}
},
"_source": {
"include": [
"group"
]
}
}
这种方式较精确, 但是查询["a","b","c"]
, 只要文档字段有符合其中一个, 那么就会返回, 是一种包含操作, 即我们返回的文档可能是["a"], 那么我们想只找"a","b","c"都有的文档, 怎么办?以下:
POST /a/b/_search
{
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"term": {
"group": "a"
}
},
{
"term": {
"group": "b"
}
},
{
"term": {
"group": "c"
}
}
]
}
}
}
},
"highlight": {
"fields": {
"*": {}
}
},
"_source": {
"include": [
"group"
]
}
}
这下就精确了.
3.6.统计聚合
我们统计聚合如下:
POST /a/b/_search
{
"aggs": {
"status": {
"terms": {
"field": "group"
}
}
},
"size": 0
}
四.批量翻页和插入scroll/bulk
POST /a/b/_search?scroll=1m //第1次请求
{
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "job_type"
}
}
]
}
},
"sort" : ["first_create_at"],
"size": 10
}
返回结果包含:_scroll_id
,base-64编码的字符串
POST /_search/scroll //后续请求
{
"scroll": "1m",
"scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs="
}
然后处理增加字段后/bulk
批量插回.
POST /_bulk
{"update":{"_index":"a","_type":"b","_id":"%s"}}\n
{"doc":%s,"doc_as_upsert":true}\n
{"update":{"_index":"a","_type":"b","_id":"%s"}}\n
{"doc":%s,"doc_as_upsert":true}\n
五. 倒排索引
我们来进一步分析字段的索引!
请参考: http://www.cnblogs.com/maybe2030/p/4791611.html
以下图片较长, 请耐心等待加载
ElasticSearch业务逻辑案例的更多相关文章
- RxJava系列番外篇:一个RxJava解决复杂业务逻辑的案例
之前写过一系列RxJava的文章,也承诺过会尽快有RxJava2的介绍.无奈实际项目中还未真正的使用RxJava2,不敢妄动笔墨.所以这次还是给大家分享一个使用RxJava1解决问题的案例,希望对大家 ...
- shell脚本就是由Shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。
shell脚本?在说什么是shell脚本之前,先说说什么是shell. shell是外壳的意思,就是操作系统的外壳.我们可以通过shell命令来操作和控制操作系统,比如Linux中的Shell命令就包 ...
- MyBatis知多少(6)表现层与业务逻辑层
表现层 表现层负责向最终用户展示应用程序的控制方式以及数据.它还要负责所有信息的布局和格式.今天,商业应用程序最流行的表现方式应该算是Web前端了,它使用HTML和JavaScript并通 过Web浏 ...
- springMvc基本注解:@Component、@Repository(持久层) 、@Service(业务逻辑) 、@Controller(控制层)
1.@Controller(控制层) :就是action层 2.@Service(业务逻辑) :业务逻辑层,负责处理各种控制层的操作 3.@Repository(持久层) :称为“持久化”层,负责对数 ...
- 如何利用动态URL提升SEO及处理业务逻辑
如果你正在建设一个新网站或者对现有网站重新设计,我们认为应该将网站的 URL 转换为用户友好的 URL,或搜索引擎友好的 URL,这类 URL 也称为语义 URL(Semantic URL).哪些UR ...
- 从App业务逻辑中提炼API接口
2.1 从App业务逻辑中提炼API接口 业务逻辑思维导图 功能-业务逻辑思维导图 基本功能模块关系 功能模块接口UML(设计出API) 在设计稿标注API 编写API文档 2.2 设计API的要点 ...
- MVC5 网站开发之四 业务逻辑层的架构和基本功能
业务逻辑层在Ninesky.Core中实现,主要功能封装一些方法通过调用数据存储层,向界面层提供服务. 目录 奔跑吧,代码小哥! MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 ...
- 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 6 - 业务逻辑
Part 3: 设计逻辑层:核心开发 如前所述,我们的解决方案如下所示: 下面我们讨论整个应用的结构,根据应用中不同组件的逻辑相关性,分离到不同的层中,层与层之间的通讯通过或者不通过限制.分层属于架构 ...
- 9.1.3 .net framework通过业务逻辑层自动生成WebApi的做法
首先需要说明的是这是.net framework的一个组件,而不是针对.net core的.目前工作比较忙,因此.net core的转换正在编写过程中,有了实现会第一时间贴出来. 接下来进入正题.对于 ...
随机推荐
- MOOC C++笔记(四):运算符重载
第四周:运算符重载 基本概念 运算符重载,就是对已有的运算符(C++中预定义的运算符)赋予多重的含义,使同一运算符作用于不同类型的数据时导致不同类型的行为. 运算符重载的目的是:扩展C++中提供的运算 ...
- java反射机制,以及对反射机制的了解
反射是什么?反射有什么用?我相信大家在开始学的时候都会有疑惑,直到如今我学的还不够深入只能简单的说说反射的作用,理论的我也听得很迷糊,接下来我就以几个例子来 写写反射的用处: 494696003群,有 ...
- ReentrantLock API
java可重入锁,简单几个小案例,测试特性. 1.尝试锁 tryLock package com.cn.cfang.ReentrantLock; import java.util.concurren ...
- 线上CPU飙升100%问题排查,一篇足矣
一.引子 对于互联网公司,线上CPU飙升的问题很常见(例如某个活动开始,流量突然飙升时),按照本文的步骤排查,基本1分钟即可搞定!特此整理排查方法一篇,供大家参考讨论提高. 二.问题复现 线上系统突然 ...
- 多源最短路径算法—Floyd算法
前言 在图论中,在寻路最短路径中除了Dijkstra算法以外,还有Floyd算法也是非常经典,然而两种算法还是有区别的,Floyd主要计算多源最短路径. 在单源正权值最短路径,我们会用Dijkstra ...
- 深度汉化GCompris-qt,免费的幼儿识字软件
1 需求 因为有个小孩上幼儿园了,想开始教他一些汉语拼音和基本的汉字,但通过一书本和卡片又有些枯燥乏味,于上就上网搜索一些辅助认字的应用,还购买了悟空识字APP,在用的过程中发现他设置了很严格的关卡, ...
- Android测试环境配置
测试是软件开发中非常重要的一部分,Android中是使用junit测试框架,本文使用的是junit4和Android Studio.Android测试主要分两类本地测试和Instrumented测试, ...
- 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU特性那些事(5)- 划时代新品RT1170
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列MCU的划时代新品i.MXRT1170. 自2017年开始,每年的6月25日恩智浦都会在北京举行微控制 ...
- Redis的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB 和 AOF 机制: 1.RDBRedis DataBase)持久化方式:是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间点 ...
- Scala 学习笔记之集合(8) Try和Future
import util._ import concurrent.ExecutionContext.Implicits.global import concurrent.Future import co ...