深度解析Lindorm全文索引(SearchIndex)特性

一、引言

Lindorm提供海量数据下的高性能、低成本、弹性的存储能力,被广泛应用在风控、推荐、历史订单等场景中,成为阿里经济体的核心数据库产品之一。随着集团云化的战略推进和云原生时代的到来,为了更好的服务内外客户,Lindorm品牌全新升级,融合宽表、时序、搜索、文件四种模型,演变为一款云原生多模数据库,关于Lindorm的产品介绍,可参考存的起,看得见—云原生多模数据库Lindorm技术解析

宽表模型兼容开源HBase接口,适合存储海量数据,并提供极高吞吐的键值查询。本篇文章介绍的全文索引SearchIndex是依托搜索引擎为宽表模型提供更高级的查询能力,是Lindorm宽表引擎和搜索引擎的深度融合特性。本文主要介绍SearchIndex的技术原理和核心能力,分享过去我们遇到的关键问题以及解决思路。

  • 什么是SearchIndex?
    1)Lindorm宽表的一种新型索引,用来加速多条件查询,是Lindorm在数据可见性上的全新探索。
    2)索引引擎基于Lucene,可同时提供倒排和正排索引,具备多维查询、文本检索等基础功能。

二、现状与挑战

2.1 多样化的数据查询需求

Lindorm依托其弹性的扩展能力和低成本,成为海量数据存储的首选,在过去的2020年,Lindorm数据存储规模接近400PB,平均压缩率在5:1。在海量数据存储的背景下,伴随着云原生、5G/IOT时代的到来,新的业务模型在不断涌现,除了简单的主键查询和范围查询外,简单分析、多维检索成为业务的基本需求。

以Lindorm客户收钱吧的线上订单场景为例,每天接近5千万笔订单数据,需要保存3年之久,通过Lindorm的冷热分离、生命周期自动管理以及高效压缩显著的降低了业务的存储成本,良好的扩展性可以随时应对业务峰值,毫秒级获取订单详情。随着业务的发展,订单系统需要提供更丰富的查询入口,帮助商家从多个维度检索出订单列表,并进行基础的统计分析,可以结算每天的营业总额、总的订单数,以及历史的曲线变化。如何高效的支持这些多样化的查询是Lindorm在服务众多客户过程中需要重点解决的,常见的一些查询需求如下:

1)多维查询。 即席查询(adhoc),一般是不固定的列随机组合。
2)count计数。 获取数据表的总行数,或者返回一次查询命中的数据条数。
3)指定列排序。 按照指定列降序或升序,比方说按照订单时间降序输出结果。
4)分词检索。 支持文本字段的分词检索,返回相关性较高的结果数据。
5)统计聚合。 按照某个字段进行聚类统计,求取sum/max/min/avg等,或者返回去重后的结果集。
6)模糊查询。 查询以'阿里'开头的数据,可以匹配出'阿里巴巴'的结果集,类似MySQL的like语法。

诸如此类的海量数据低成本存储+检索多样化的需求成为越来越多业务的基本诉求,如何在Lindorm系统本身的高扩展、低成本的优势之上,同时去支撑业务的多样化查询场景,成为客户和我们一直思考去解决的问题。

2.2 Lindorm现有方案

面对复杂的查询需求,在Lindorm上的用户通常会选择如下几个解决方案:

1)主键索引。Lindorm天然具备主键索引,可以很好的满足业务基于主键的整行匹配、前缀匹配、范围查询等场景。
2)原生二级索引。在多维查询的场景中,通过创建多个二级索引来满足。二级索引适用查询模式较为固定的场景,一个主表建议控制在5个二级索引表以内最佳。
3)聚合Aggregate。使用Lindorm Aggregate语法,支持count/sum/avg/min/max。
4)自然排序。当前仅支持主键列或索引列排序,按照最左前缀匹配,只能排序等值查询后的第一个主键列或索引列。例如:

CREATE TABLE myTable (pk1 int, pk2 text, c1 text, c2 bigint, PRIMARY KEY (pk1, pk2));
SELECT * FROM myTable WHERE pk1=? ORDER BY pk2;   // 合法
SELECT * FROM myTable WHERE pk1=? ORDER BY c1;   // 非法
CREATE INDEX myIndex ON myTable (c1, c2);
SELECT * FROM myTable WHERE c1=? ORDER BY c2;   // 合法
SELECT * FROM myTable WHERE c2=? ORDER BY c1;  // 非法

主键和索引的设计遵循最左前缀匹配,关于二级索引可参考高性能原生二级索引

5)Like查询。对于字符串类型的数据,可以使用Lindorm Like语法实现模糊查询,支持通配符%_

上述方案最大的优点就是简单、开发便捷,但不可避免在规模和成本制约下,会存在瓶颈,例如全表的count需要消耗大量IO资源、过多的二级索引会导致写入吞吐的下降。如何在有限的资源下尽可能高效的满足业务复杂查询的诉求成为我们下一步重点考虑的问题,业界同样也面临这样的问题。

2.3 业界解决方案

搜索引擎是解决复杂查询的最佳实践之一,业界通常会选择将数据转储到搜索引擎Elasticsearch/Solr中,或者内置Lucene引擎来提供复杂查询的支持。

1)数据转储到外部搜索引擎

1.1)应用双写
数据双写是最为简单的实现方式,通过前端接入Kafka等消息系统,多个消费者双写到不同的应用系统中。在我们接触的客户中,有非常多的业务是双写HBase和Elasticsearch/Solr,查询时,先从搜索引擎中查询出主键,然后回查HBase获取完整的结果数据。虽然简单快捷,但不可避免会面临非常多的痛点。

  • 开发成本高。需要学习理解两套系统的API,多语言的支持也不尽相同。
  • 资源消耗高。双写相当于写入双份的数据,客户端需要更多的资源才可以确保两套系统的写入均衡,防止出现木桶效应影响全局的写入稳定。
  • 缺少数据一致性保障。任何一个系统的数据写入失败需要自主处理重试,否则会导致数据丢失;HBase支持部分更新,而搜索引擎只能整行更新,因此更新场景必须读取出原始数据才能组装出索引数据,这在高并发的写入场景下很容易出现数据不一致问题。

1.2)数据自动同步(LilyIndexer+Apache Solr)
开源HBase可以借助LilyIndexer将数据同步到Solr中提供全文检索的能力,它的基本架构如下图,整体的流程是:先通过HBase Replication(数据复制)将表的WAL日志数据推送到LilyIndexer,LilyIndexer按照事先配置好的映射Schema解析出数据,最后同步写入到Solr中。

深度解析Lindorm全文索引(SearchIndex)特性

通过自动同步省去了业务客户端的开发成本,但同时也会带来维护的复杂。

  • 运维复杂,难以维护。LilyIndexer已经多年无人维护,链路操作比较繁琐,需要同时操作三个服务HBase/LilyIndexer/Solr。目前主要是大数据发布商Cloudera内部维护,没有形成应用生态。
  • 同步效率低,链路不可见。一行数据写入到HBase后,需要经过多次序列化/反序列化才能写入Solr,整个过程高度依赖HBase的Replication能力,很容易达到瓶颈;同时,每个HBase表的Replication通道彼此隔离,如果有多张表需要同步,那么一个WAL将会被重复读取多次,存在严重的木桶效应,给HDFS带来无效的IO压力。并且同步链路是个黑盒,一旦出现同步阻塞,只能从后台运行日志中查看原由。
  • 数据一致性难以保障。HBase支持多版本,每个KV都具有独立的时间戳ts,可以确保时间戳ts大的优先可见。但是在Solr中并没有时间戳的概念,数据以后写的为准。加之HBase Replication消费WAL存在乱序的问题,就会导致数据写入Solr的顺序错乱,引起HBase表的数据与Solr索引数据的不一致。

2)内置搜索引擎
通过对架构重新设计,内嵌搜索引擎的支持,从而达到系统的整体统一,这样既能继承原始的查询功能,又可以扩展支持较为复杂的查询。例如MongoDB,开源的版本不具备全文检索的能力,只提供基础的Text索引功能,而它背后的公司MongoDB Inc.推出的企业版Atlas新增一个Search的功能,依托Lucene实现了全文检索的能力。最初由Facebook开源的分布式NoSQL数据库Cassandra同样是在架构上进行升级,开源的Solandra方案便是引入搜索引擎Solr解决复杂的查询问题,其背后的公司Datastax也是在此基础上推出商业化的DSE Search特性,它的基本架构如下图,通过深度修改Cassandra和Solr的源码,将两者融合在一个进程中提供服务,对外提供统一的CQL查询语法。

深度解析Lindorm全文索引(SearchIndex)特性

将搜索引擎与原始架构深度融合是一种非常好的方案,但也会面临一系列的问题。

  • 系统隔离性。运行时的部署形态能否做到真正的隔离,搜索引擎的查询对资源要求较高,如果缺少合理的资源配比,很容易出现资源的浪费和运行时的相互影响。
  • 数据一致性。因为Lucene天然的设计约束,数据写入后无法立即可见,即使内置搜索引擎没有了数据同步的延迟,依然无法提供强一致的语义,业务必须忍受最终一致带来的访问延迟。

通过对业界方案的调研分析,我们看到了一些优秀的实践以及融合Lucene过程中会存在的一些问题,为了解决这些问题,我们期望在Lindorm上设计一种新的索引,以数据库特性的方式即开即用,帮助业务解决海量数据下的复杂查询问题。

三、Lindorm SearchIndex 设计思路

索引通常用来加速查询,可以通过增加一种新的索引类型来解决海量数据的复杂查询问题,Lindorm作为一个多模数据库,原生支持搜索引擎,天然具备全文索引能力。因此,我们通过融合搜索引擎,为Lindorm宽表增加了一种新型索引:SearchIndex。使得业务不感知底层的多个引擎以及数据的流转,只需要申请一个新的索引即可解决复杂的查询问题,就像使用Lindorm二级索引一样方便快捷。SearchIndex重点构建以下能力:

1)统一元数据
多套系统运维复杂的根因是各自的元数据不统一,需要使用各自专用的命令才可以操作,例如在一个系统中建完表,还需要在另外一个系统中建索引。通过维护统一的分布式元数据,我们可以屏蔽掉不同引擎间的Schema差异,提供统一的命令完成DDL类的操作。

2)统一接口
多个系统间的接口存在差异,通过实现一套专有的统一接口可以有效降低开发的复杂度,但这也需要业务学习和理解新的接口,应用开发成本没有明显的降低。SQL作为众多数据库系统的开发语言,使用和学习成本都较低,Lindorm SearchIndex原生支持类SQL接口:CQL,业务开发过程中不感知索引的存在,在使用体验上与原始的宽表访问保持一致。

3)强一致性
数据在多个引擎间流转必然会涉及到一致性问题,通常只能提供最终一致性的语义,数据的正确性和访问延迟无法有效保障。Lindorm SearchIndex提供了最终一致性和强一致性两种语义,对于访问量大、数据延迟性要求不高的场景采用最终一致性,可以提供非常高的吞吐和可用性,而业务访问延迟敏感的业务可以选择强一致性模型,数据写入成功后,索引立即可查。

4)资源隔离
异构系统对资源的使用各不相同,必须建立有效的隔离机制确保资源使用最大化,Lindorm通过存储和索引分离的模式来保障系统的健壮和弹性。宽表引擎负责存储原始数据,具备极低的存储成本,搜索引擎负责索引和检索,两个引擎可以配置不同的CPU、内存资源,并且可以独立扩缩容。

接下来,我们将重点介绍SearchIndex的架构设计以及具体的功能实现。

四、Lindorm SearchIndex 功能解析

4.1 使用举例

SearchIndex的使用非常简单,创建索引表时只需要枚举出索引列名即可,查询时不需要感知索引表的存在。下面先给出一个具体的例子,介绍如何使用Lindorm CQL(CQL是Cassandra的查询语言,Lindorm无缝兼容Cassandra API)操作SearchIndex。

深度解析Lindorm全文索引(SearchIndex)特性

  • 原始表
CREATE TABLE myTable (
    id bigint,
    name text,
    age int,
    sex text,
    city text,
    address text,
    PRIMARY KEY (id)
) WITH compression = {'class': 'ZstdCompressor'};
  • 需求

对 姓名(name)、年龄(age)、性别(sex)、城市(city)、地址(address) 建立全文索引

CREATE SEARCH INDEX myIndex ON myTable WITH COLUMNS (name, age, sex, city, address);

注意:索引列的先后顺序不影响,即索引列(c3, c2, c1)与索引列(c1, c2, c3)最终的效果是一致的。

  • 查询

1)标准查询语句

模糊查询:SELECT * FROM myTable WHERE name LIKE '小%'
多维查询排序:SELECT * FROM myTable WHERE city='杭州' AND age>=18 ORDER BY age ASC
多维查询翻页:SELECT * FROM myTable WHERE name='小刘' AND sex=false OFFSET 100 LIMIT 10 ORDER BY age DESC

查询编译层会自动将符合条件的查询路由到索引节点,除了上述比较Native的查询方式,我们同时提供更贴近搜索的查询方式search_query,后续的章节我们也会介绍到。

2)高级查询语句

多维查询排序:SELECT * FROM myTable WHERE search_query='+city:杭州 +age:[18 TO *] ORDER BY age ASC'
文本检索:SELECT * FROM myTable WHERE search_query='address:西湖区'

从上面的例子可以看到,SearchIndex的使用非常简单,基本可以做到拿来即用。

4.2 适用场景

SearchIndex在阿里内部已经成功应用多个业务场景,当前该特性在公有云上已经发布,支持的重要功能列表如下:

1)多维查询:多个条件任意组合的精确查询、范围查询等。
2)通配符查询:* 代表任意个字符;? 代表任意单个字符。
3)统计聚合:求最小值、求最大值、求和、求平均值、统计行数。
4)排序分页:任意索引列的排序输出。
5)文本分词:支持中文/英文分词,分隔符分词,拼音分词等。
6)地理位置:距离查询、长方形/多边形范围查询。(即将到来)

有了这些功能,可以很容易的将Lindorm应用到多样化的业务场景中,当前我们已经在公有云上积累了大量的客户案例,经典的使用场景主要有以下几个:

1)订单详情,例如物流订单、交易账单,支持订单的多维查询、排序等。
2)标签画像,例如基于商家对买家进行标签圈选,定向投递信息。
3)文本搜索:例如日志分析,异常信息检索等。

4.3 实现原理

Lindorm作为一款多模数据库,同时支持多种模型,在总结过往的经验和业界实践后,我们将搜索引擎与宽表模型深度融合,对外提供简单易用的SearchIndex,整体的分层架构如下:

深度解析Lindorm全文索引(SearchIndex)特性

  • 查询接入:由多个QueryProcessor节点组成,主要负责查询接入,进行SQL解析,基于RBO自动选择合适的索引。
  • 索引预处理:基于索引列的元信息将新插入或者更新的原始数据转换为索引数据,并且针对不同的场景可以选择与之匹配的Mutability属性,比较典型的例如日常监控,数据写入后不更新,可以选择Immutable模式,直接生成索引原始数据;而那些有状态的数据,大多需要局部更新,此时通过回读历史数据组装成索引原始数据,并且能够支持业务自定义时间戳的写入,确保数据不乱序。
  • 索引同步:对于最终一致模式(默认),LTS(Lindorm Tunnel Service)作为Lindorm生态的数据同步服务,具备高效的实时同步和全量迁移能力。可以实时监听WAL的变化,将索引原始数据转换后写入到搜索引擎,同时支持一读多写,即一份WAL可以同步到多个索引表中,极大提升同步效率;对于强一致模式,索引原始数据构建完毕后同步写入到搜索引擎,由搜索引擎实时生成全文索引,为业务提供写入即可查的强一致体验。
  • 索引引擎:由多个节点组成的分布式Lucene集群,数据按照Hash或者Range来划分为多个Shard,对外提供全文检索能力。
  • 索引存储:索引数据存储在分布式文件系统Lindorm DFS上,存算分离的架构具有极好的扩展性,同时存储层的透明压缩和智能冷热分离可以显著降低索引的存储成本。

4.4 核心特性

4.4.1 Online DDL Operations

作为一个分布式数据库,Lindorm可以横向扩展支持高达亿次每秒的处理能力,如果我们的索引DDL需要阻塞DML,对高并发的业务应用影响将会被放大。借助Lindorm的分布式元数据管理,SearchIndex通过合理的扩展,可以支持在线DDL操作,并且不会破坏数据的完整性。

1)动态增加、删除索引列
在宽表的应用场景中,列可能不会固定,尤其是标签画像场景,需要经常性的增加或删除索引列。SearchIndex提供Java API/CQL接口来动态操作索引列。

2)在线变更索引列属性
每个索引列支持多种属性:indexed(是否索引,默认true)、stored(是否存储原始值,默认false)、docvalues(是否维护正排索引,默认true)、分词类型等。例如某个索引列起初并未设置stored,那么在索引表中是不会存储原始值的,服务端会自动回查Lindorm宽表获取原始数据。此时,可以通过接口变更索引列的stored为true。

3)动态修改压缩
Lindorm宽表在创建时可以设置压缩算法(例如ZSTD、Snappy),也可以创建表后动态修改。SearchIndex是一个独立的索引表,底层依赖Lucene,仅支持LZ4和ZLIB两种压缩算法,为了保证原始主表与索引表的属性统一,我们通过修改Lucene,让其支持ZSTD、Snappy压缩算法。因此,在修改原始主表压缩算法时,也会联动修改SearchIndex,有效降低索引的存储大小。

4)动态修改TTL
为了自动淘汰历史数据,Lindorm支持动态修改表的TTL,例如设置TTL=30days,代表从此刻起30天前的数据将会被淘汰,并且无法查询。我们在Lucene的基础上实现了行级TTL能力,可以与原始主表的TTL联动,自动淘汰过期数据,确保主表和索引表的数据一致。

5)动态修改索引表状态
索引表的状态主要有三种:DISABLED(不可写,不可查)、BUILDING(可写不可查)、ACTIVE(可写可查)。在创建、删除索引或者对历史数据构建索引时,我们经常需要动态变更索引的状态,此时也不能够影响到运行中的DML请求。

4.4.2 多一致性

Lindorm宽表针对不同的业务场景,使用一套架构提供了不同的数据一致性模型,常用的是EC和SC模式:

1)最终一致 Eventual Consistency
数据写入后,可能需要等待一段时间后(ms,通常就近读取最新数据)才能被读到,可以规避任何毛刺和抖动。

2)强一致 Strong Consistency
数据写入后,可以立即读到。

在设计SearchIndex时,针对不同的业务场景,我们也提供了多一致性的支持。

1)最终一致性(默认)
1.1)用户写入操作成功返回后,原表数据立即可见,索引表数据不保证立即可查,需要等待一定的时间(可调节的时间,最低可配置为1秒)。
1.2)可见时间=LTS同步时间(ms)+搜索引擎数据可见时间(最低1秒)。

2)强一致性
2.1)用户写入操作成功返回后,主表和索引表中的数据一定可见,依赖Lindorm Search的实时可查特性,可参考下面章节的介绍。
2.2)写入过程中,或者写入未成功(抛错或者超时)时:不保证主表和索引表数据同时可见,但可以保证最终一致性,主表和索引表数据要么全执行成功,要么全不执行。

深度解析Lindorm全文索引(SearchIndex)特性

4.4.3 可选的索引构建成本

索引可以加速查询,助力业务进一步挖掘数据的价值,但它不是银弹,会带来写入成本和存储成本的增加。我们可以通过多种高效的压缩算法显著降低索引的存储体积,但如何降低索引构建对写入吞吐的影响呢?

深度解析Lindorm全文索引(SearchIndex)特性

上面是数据写入的主要流程,其中索引WAL的构建快慢将直接影响到原始数据的写入性能。Lindorm宽表是一个KV数据库,天然支持更新部分列,但是搜索引擎Lucene只能整行更新,不能够局部更新。因此,在构建索引时需要回读原表获取历史数据,才能够拼接出完整的索引WAL。我们将这个回读操作按照业务场景进行分类,支持不同的选择。

1)IMMUTABLE(成本最低)
1.1)适用场景:数据只增不删的场景(可以TTL淘汰数据)。例如监控数据/日志数据,数据写入后不会更新和删除。
1.2)索引构建非常高效,不需要回查旧数据,直接依据当前的数据生成索引。

2)MUTABLE_LATEST(成本中等)
2.1)适用场景:普适的场景,大众的选择(除UDT)。
2.2)例如索引列为c1,c2,第一次写入c1列,第二次写入c2列。那么在第二次写入c2的值时,需要读出原始的c1值,才能够拼接出完整的索引数据c1,c2。

3)MUTABLE_ALL(成本最高)
3.1)适用场景:写入数据时,业务自定义时间戳(User-Defined Timestamp)。例如:全量任务和增量并存的场景,往往需要在全量任务时携带时间戳,这样可以确保不会覆盖增量写入的数据
3.2)存储引擎层每个KV都有时间戳,如果业务写入时没有显示的设置,服务端会自动设置为系统时间戳,遵循"时间戳大的优先可见"的原则。
3.3)业务自定义时间戳的写入,在构建索引时需要获取到所有的历史数据(包括删除的数据),才能准确判断当前的写入是否为有效数据。如果时间戳小,则直接丢弃掉,不构建索引。

4.4.4 高效同步

在最终一致性的模型中,索引数据同步依赖LTS服务。LTS服务作为Lindorm生态的数据通道,具备高效的实时同步和全量迁移能力,写入宽表的数据,可以在毫秒内感知到,快速的同步到搜索引擎中。

1)同步可视化。LTS提供WEB访问,可以查看到索引同步的详细信息。例如同步的耗时、索引表信息、同步的数据量等。另外,LTS可以将这些信息对外吐出监控指标,对接告警体系,实时监测同步链路的健康度。

2)同步高效率。LTS内部通过高并发的生产者/消费者模式,支持快速消化大量的数据,一份WAL只需要读取一次。并且支持横向扩展,新加入的节点可以快速加入到同步链路中,加速索引数据的同步。

3)WAL保序。通过隐藏的时间戳属性,保证在宽表中先写入的数据先写入搜索,后写入的数据后写入搜索,确保宽表和搜索的数据一致性,彻底解决LilyIndexer存在的数据错乱问题。

4)全量构建快。对于已有的历史数据,可以借助LTS的全量任务运行机制,高效的从宽表中获取原始数据生成索引,TB级别的数据量分钟内即可完成索引构建。

5)数据快速校验。支持对已有数据的比对校验,可以快速筛选出不一致的索引数据,帮助业务及时发现问题。

4.4.5 索引实时可见(RealTime Search)

写入成功后的索引数据可以立即可查,我们称之为索引的实时可见,是一种强一致的模型。SearchIndex底层依赖Lucene,Lucene有一个明显的"缺陷":数据写入后不能立即可查,必须要显示的执行Flush或者Commit操作才可以查询到。这导致基于Lucene的服务无法应用到实时业务场景,只能适用于监控、日志等弱实时的场景。在业界,基于Lucene的分布式搜索引擎Elasticsearch/Solr为了缓解这个问题,提供近实时查询(NRT)功能,可以确保索引数据在某个时间范围内(通常在秒级)一定可查,但还是达不到实时性的要求。

为了解决写入的数据无法立即可查的问题,我们基于Lucene实现了一种索引实时可见的方案,通过精细化的数据结构设计和动态的内存管理机制,可以保证索引数据一旦写入成功后可以立即查询到,真正做到实时性。

4.4.6 CQL API

CQL是Cassandra的官方查询语言,是一种适合NoSQL数据库特点的SQL方言,由于Lindorm无缝兼容Cassandra,面向客户我们默认推荐使用CQL来访问SearchIndex。当然,集团内部用户也可以继续使用Lindorm的TableService API来访问SearchIndex

1)DDL

1.1)创建索引 
CREATE SEARCH INDEX index_name [ IF NOT EXISTS ] ON [keyspace_name.]table_name
      | [ WITH [ COLUMNS (column1,...,columnn) ]
      | [ WITH [ COLUMNS (*) ]

1.2)删除索引

DROP SEARCH INDEX [IF EXISTS] ON [keyspace_name.]table_name;

1.3)重构索引

REBUILD SEARCH INDEX [IF EXISTS] ON [keyspace_name.]table_name;

1.4)修改索引

ALTER SEARCH INDEX SCHEMA [IF EXISTS] ON [keyspace_name.]table_name
      ( ADD  column_name
      | DROP column_name) ;

2)DML
2.1)标准查询,WHERE后面紧跟具体的条件。
2.2)search_query查询,语法如下:

SELECT selectors
       FROM table
       WHERE (indexed_column_expression | search_query = 'search_expression') 
       [ LIMIT n ]
      [ ORDER BY column_name ] 

当标准的查询语法无法满足检索需求时,可以考虑通过search_query来直接从搜索引擎中检索数据,使用的语法也是Lucene的语法。例如,下面的用例中,相当于检索city为'hangzhou',并且age在1到18(包含)的数据。

SELECT name,id FROM myTable  WHERE search_query = '+city:hangzhou +age:[1 TO 18]';

详细的CQL语法,可参考语法介绍

五、案例介绍

Lindorm经过多年的发展和历练,在集团内部和公有云形成了良好的口碑,通过不断的夯实存储引擎,让业务数据真真正正的"存得起",海量数据存储找Lindorm已成为各个业务选型的重要参考,非常感谢各位业务方的信任与支持。除了支持淘宝、支付宝、菜鸟、优酷、高德等业务中的核心应用外,我们也在不断探索新的业务场景,今天介绍的SearchIndex特性可以进一步让业务数据"看得见",只有看得见才能挖掘数据的价值,形成数据驱动业务的良性循环。特性上线之后受到了很多用户的喜爱,在此也列举下当前在线上跑的一些场景,帮助大家进一步了解SearchIndex的使用场景。

5.1 订单场景

不管是传统行业,还是互联网行业,订单数据的存储是核心需求。而且订单数据往往有其特殊的天然属性:

  • 高增长:数据可能随时会爆发式的增长,例如双11或大促节日。
  • 低成本:订单数据一般不会直接产生经济效益,是业务对外呈现的附加价值,需要低成本存储。
  • 多维查询:对于C端用户而言,往往会从不同角度对订单进行分类、标记以及查看和过滤自己的订单。

在之前,面对上面的诉求,一般的解决方案就是MySQL+搜索引擎。业务双写到两个系统中,或者借助binlog进行实时同步,查询时分别从不同的系统中获取结果。随着数据量的增长,可能会演变为MySQL热数据+Lindorm冷数据+搜索引擎的架构,基于多套系统可以有效解决业务问题,但需要面临多套系统维护的时间成本和人力成本。

现在,一套Lindorm即可解决问题,不用关心数据的流转,统一的API访问。
1)通过冷热分离、压缩优化等手段显著降低存储成本。
2)横向弹性扩展适应海量数据的写入。
3)SearchIndex CQL提供丰富的查询语法。

客户群体:物流、第三方支付、移动出行。

深度解析Lindorm全文索引(SearchIndex)特性

某物流公司基于Lindorm实现的订单查询系统。

5.2 用户画像

用户画像的数据一般有两种:一个是基础数据,另一个是经过分析得到的标签数据。这些数据可以被应用到营销、推荐等场景中,可以助力企业营收快速增长。画像数据的主要痛点如下:

  • 数据量大:画像数据与用户基数强相关,往往在千万甚至亿级别,而且数据维度非常高,在我们服务的客户中,有的场景支持的标签数在5000个以上。
  • 高并发。画像数据通常需要全量刷新,需要在基线的时间内完成才能有效辅助后续的推荐、广告投放等。
  • 动态列。数据维度在不断的变化中,因此需要支持动态增/删列。
  • 多维查询。面向不同的业务需求,画像数据查询需求也会有差异,运营人员通常会统计任意一个维度的数据。

画像场景一般没有强事务需求,而是大数据量、高并发读写的场景,关系数据库不太适合。Lindorm作为一款NoSQL数据库,非常适合这样的场景。
1)多列族、动态列、TTL等特性,适合表结构不固定,经常需要进行变更的业务场景。
2)高性能吞吐。
3)SearchIndex CQL支持任意维度的查询和统计。

客户群体:在线教育、互联网车险。

深度解析Lindorm全文索引(SearchIndex)特性

某在线教育公司基于Lindorm实现的学生画像系统。

5.3 日志检索

日志的来源非常广泛,例如系统日志、数据库审计日志、用户行为日志等,这些数据在互联网公司中通常存储于开源Elasticsearch(ES)中,借助ELK体系构建一站式的日志平台。但ES的存储成本是非常高的,而且存储和计算往往需要同机部署,在海量数据下系统运维面临非常多的挑战,数据迁移、节点扩缩容等都需要人工介入。多模数据库Lindorm的SearchIndex是日志检索场景的更优选择,通过宽表引擎存储海量数据降低成本,搜索引擎构建合适的索引加速查询,统一的API操作进一步降低业务开发成本。

深度解析Lindorm全文索引(SearchIndex)特性

客户群体:日志数据量大、成本敏感的客户。

六、总结与展望

SearchIndex作为Lindorm宽表的一种新型索引,进一步增强了宽表的查询能力,业务使用统一的CQL API即可享受SearchIndex带来的查询便利,无需感知底层的多模引擎以及数据同步问题。未来,我们将在以下方面继续发力:
1)持续丰富SearchIndex的查询能力,例如:支持地理位置查询等。
2)SearchIndex Serverless隔离调度,持续降低业务接入成本。
3)融合时序引擎,加速时序引擎的tag检索等。

七、结语

感谢大家百忙之中阅读文章,同时非常欢迎大家咨询使用,SearchIndex的使用文档,可参考使用手册,技术交流欢迎加入钉群:35977898

同时,也热烈欢迎有兴趣的同学加入我们,一起建设云原生多模数据库Lindorm,职位介绍请参考链接

上一篇:学习:为什么要使用抽象类


下一篇:C# 如何获取某个类型或类型实例对象的大小