目前大部分的前后端协作方式仍然是后端根据业务需求给前端提供接口返回特定数据,但是Elasticsearch却为我们提供了可能来自己根据需要搜索筛选以及更新数据。比如查询商品列表,我们可以自己根据品牌、入库时间、颜色等条件筛选获取数据。
Elasticsearch是什么
Elasticsearch是一个基于Lucene的搜索服务器,简称ES。它提供了一个分布式多用户能力的全文搜索引擎,每一个字段都可以被搜索到,且可以结构化检索,简单地使用JSON就可以通过HTTP请求来索引数据。由于本文并非从零开始的Elasticsearch教学,所以关于安装配置等问题这里按下不表,我们直接进入正题,去看看它都可以怎样使用。
文档及元数据
在Elasticsearch中的每一个基础单元我们称之为文档,文档中的数据是由键值对组成的JSON对象。和我们从前接触的JSON对象一样,值可以是字符串、数字、布尔类型、对象或数组。
1 | { |
除数据外,文档中还有一些元数据用以帮我们检索到数据,三个必须的元数据如下:
| 元数据 | 说明 |
|---|---|
| _index | 文档存储的地方(索引) |
| _type | 文档代表的对象的类(类型) |
| _id | 文档的唯一标识 |
其实这有点像我们在电脑中存储文件,_index就好像磁盘,_type则是分门别类的文件夹,而_id就是文件名,三者结合一定能确定文档,就好像根据文件路径查找一样。
查询
Elasticsearch提供了强大的全文搜索能力,从简单的文档查询、模糊匹配到组合条件结构化查询,完全可以满足我们的各种需求。
查询索引及类型
/_search:在所有索引的所有类型中搜索
/gb/_search:在索引gb的所有类型中搜索
/gb,us/_search:在索引gb和us的所有类型中搜索
/g*,u*/_search:在以g或u开头的索引的所有类型中搜索
/gb/user/_search:在索引gb的user类型中搜索
/gb,us/user,tweet/_search:在索引gb和us的user和tweet类型中搜索
/_all/user,tweet/_search:在所有索引的user和tweet类型中搜索
查询子句
term
用以精确匹配值:
1 | { "term": { "store_id": 330001 }} |
当文档的数据结构存在多层,例如:
1 | { |
我们想在众多NBA球队中查到主教练是卡莱尔的球队就可以这样写:
1 | { "term": { "member.coach": "Rick Carlisle" }} |
层级再多就继续追加,后面的match语句也是一样。
terms
精确匹配多个值,terms的扩展,相当于多个term合并:
1 | { |
range
按照一定范围查询数据,下面的例子就是查询年龄20~30(含20)的数据:
1 | { |
gt:大于
gte:大于等于
lt:小于
lte:小于等于
exists和missing
用于查找文档中是否包含指定字段或没有某个字段:
1 | { |
match_all
查询到所有文档,是没有查询条件下的默认语句:
1 | { |
match
match是一个查询语句,可以模糊查询关键结果,Elasticsearch会根据搜索的相关度给文档定分值,相关度越高的分值越高,结果越靠前。
1 | { |
该语句可以查询到所有包含BROWN或者DOG的文档,如果要提高精度则可以使用operator参数,默认值为or,还可以修改为and:
1 | { |
如此,文档中就必须同时包含BROWN和DOG。还可以通过minimum_should_match参数控制精度,值可以设置为数字或百分比表示匹配度。
结构化语句及合并多子句
查询与过滤
我们在使用Elasticsearch时通常会在JSON接口中使用结构化语句。结构化语句分两种:结构化查询(Query DSL)和结构化过滤(Filter DSL)。 查询与过滤语句非常相似,但是它们由于使用目的不同而稍有差异。
过滤语句是为了确定是或者不是,非黑即白,有就是有。而查询语句为了找到文档会去询问匹配度如何,更适合全文搜索。由此可以看出,过滤语句是为了缩小匹配结果,只找最准确的,由于不需要额外计算相关性所以过滤语句性能更高。
结构化查询和结构化过滤需要对应的参数分别为query和filter,这使得语句创建了上下文关系,query和filter可以相互包含,相互辅助,这一点我们稍后举例。
合并多子句
出于特定化的需求,我们要将多个条件结合起来得到搜索结果,这就需要bool语句了。bool语句可以用来合并多个条件查询结果的布尔逻辑。
1 | { |
must:多个查询条件的完全匹配,相当于and,必须全部满足。
must_not:多个查询条件的相反匹配,相当于not,必须全部满足。
should:至少有一个查询条件匹配, 相当于or,至少满足一个条件。
must、must_not、should可以接受一个条件或一个条件数组。上面的例子就是查询出所有球队中不包含湖人的西部球队或排名前八的球队。由于Elasticsearch默认只返回最多10条结果,我们可以通过size参数进行修改。_source参数可以配置文档只返回特定字段。
为了优化性能我们可以在查询语句中包含过滤语句:
1 | { |
即过滤出西部队中球员名字含有Harris的球队。
嵌套对象查询
1 | { |
Elasticsearch中,对象数组会在索引中被扁平化为键值对形式:
1 | { |
因此comments中各字段之间的关联消失了,这会导致查询结果不够精确。如果想匹配同一comments的多个字段需要借助nested查询:
1 | { |
创建文档
借助elasticsearch.js这个工具库,我们可以很方便的对文档进行增删改查。
1 | client.create({ |
删除文档
1 | client.delete({ |
更新文档
1 | client.update({ |
如果是更新整个文档那就把修改后的数据全部放进body中,如果只是需要更新某些字段那就加上doc这个参数。
批量操作文档
1 | client.bulk({ |
| 参数 | 说明 |
|---|---|
create |
当文档不存在时创建文档 |
index |
创建新文档或替换已有文档 |
update |
局部更新文档 |
delete |
删除一个文档 |
批量操作文档需要指定_index、_type和_id,并且在操作后面紧跟_source请求体(delete操作除外)。
结语
到这里,有关Elasticsearch的常见用法就都介绍完了,但强大的Elasticsearch功能绝不止于此,掌握的越多我们在今后处理数据的时候就会更加得心应手。
部分内容参考自以下:
https://es.xiaoleilu.com/(特别感谢该团队的详尽翻译)
https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html