NEST - 编写查询
Writing queries
Version:5.x
英文原文地址:Writing queries
将数据索引到了 Elasticsearch 之后,就可以准备搜索它们了。Elasticsearch 提供了一个强大的查询 DSL ,使得用户可以定义个性化的搜索逻辑。这个 DSL 是基于 JSON 的,NEST 提供了 Fluent API 和 Object Initializer 语法来实现 DSL 。
Match All query
最简单的查询应该就是 match_all 了,这种查询会返回所有的文档,并给每份文档的 _score 统一赋值为 1.0
匹配的文档并不是都会在一次响应中全部返回,默认情况下只返回前十份。你可以使用
from和size来将结果分页
var searchResponse = client.Search<Project>(s => s
.Query(q => q
.MatchAll()
)
);
上面的请求会被序列化成下面这个 JSON 对象
{
"query": {
"match_all": {}
}
}
由于 match_all 查询很常见,因此前面的栗子有一个简单的写法,两种方式序列化的结果是一样的
searchResponse = client.Search<Project>(s => s
.MatchAll()
);
前面的两个栗子都是使用 Fluent API 来描述查询。NEST 还公开了一种 Object Initializer 语法去构造查询
var searchRequest = new SearchRequest<Project>
{
Query = new MatchAllQuery()
};
searchResponse = client.Search<Project>(searchRequest);
Search request parameters
search request 有一些可用的参数,你可以参阅 search 以获得详细的信息。
Common queries
默认情况下,文档会根据 _score 降序返回。每个命中的 _score 是根据文档和查询条件的匹配程度计算的关联分数。数字越大,表示越符合查询条件。
NEST 提供了许多搜索查询,它们都记录在 Query DSL 参考部分。在这里,我们要强调用户经常执行的三类查询操作
- Structured search
- Unstructured search
- Combining queries
Structured search
结构化搜索是指,查询具有固定结构的数据。日期、时间和数字都是结构化的,查询这些类型的字段通常是为了查找准确的匹配项、某个范围内的值等等。文本也可以结构化,比如博客里使用的关键字标签。
通过结构化搜索,查询的答案总是 “是” 或者 “否”。也就是说,文档要么匹配查询,要么就不匹配。
术语级别的查询通常用于结构化搜索。下面的栗子查找开始日期在指定范围内的文档
var searchResponse = client.Search<Project>(s => s
.Query(q => q
.DateRange(r => r
.Field(f => f.StartedOn)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01))
)
)
);
(1) 查找开始于 2017 年的所有的 Project
会生成以下查询 JSON
{
"query": {
"range": {
"startedOn": {
"lt": "2018-01-01T00:00:00",
"gte": "2017-01-01T00:00:00"
}
}
}
}
因为这个查询的答案只有 yes 和 no 两种情况,我自然就不需要给查询计分了。为此,我们可以把这个查询包装在一个 bool 查询 filter 子句中,这样就可以让查询在筛选上下文中执行
searchResponse = client.Search<Project>(s => s
.Query(q => q
.Bool(b => b
.Filter(bf => bf
.DateRange(r => r
.Field(f => f.StartedOn)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01))
)
)
)
)
);
{
"query": {
"bool": {
"filter": [
{
"range": {
"startedOn": {
"lt": "2018-01-01T00:00:00",
"gte": "2017-01-01T00:00:00"
}
}
}
]
}
}
}
在筛选上下文中执行查询的好处是,Elasticsearch 可以放弃计算相关性分数,还可以缓存筛选器从而获得更快的后续性能
重要:术语级别的查询没有分析阶段,也就是说不会分析查询的输入,进而在反向索引中寻找输入的精确匹配。如果一个字段在索引时进行了分析,那么再通过术语级别查询多半会失败。
当字段仅用于精确匹配时,应当考虑将其映射为
keyword类型。如果字段既用于精确匹配,又用于全文搜索,则应考虑将其映射为multi fields。
Unstructured search
另一个常见的用例是,在全文字段中搜索以查找最相关的文档。
全文查询用于非结构化的搜索。在这里,我们使用 match 查询来查找开发人员的名字中包含 “Russ” 的所有文档
var searchResponse = client.Search<Project>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.LeadDeveloper.FirstName)
.Query("Russ")
)
)
);
会生成以下查询 JSON
{
"query": {
"match": {
"leadDeveloper.firstName": {
"query": "Russ"
}
}
}
}
重要:全文查询有分析阶段。也就是说要分析查询输入,然后将分析后产生的术语和反向索引中的术语进行比较。
通过在映射期间给字段设置分析器,你可以完全控制索引和搜索阶段的分析过程。
Combining queries
一个非常常见的情况是,将不同的查询组合在一起形成一个复合查询。其中最常见的是 bool 查询
var searchResponse = client.Search<Project>(s => s
.Query(q => q
.Bool(b => b
.Must(mu => mu
.Match(m => m (1)
.Field(f => f.LeadDeveloper.FirstName)
.Query("Russ")
), mu => mu
.Match(m => m (2)
.Field(f => f.LeadDeveloper.LastName)
.Query("Cam")
)
)
.Filter(fi => fi
.DateRange(r => r
.Field(f => f.StartedOn)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01)) (3)
)
)
)
)
);
(1) 匹配开发人员的名字包含 Russ 的所有文档
(2) ... 并且开发人员的姓氏包含 Cam
(3) ... 并且项目开始于 2017
会生成以下查询 JSON
{
"query": {
"bool": {
"must": [
{
"match": {
"leadDeveloper.firstName": {
"query": "Russ"
}
}
},
{
"match": {
"leadDeveloper.lastName": {
"query": "Cam"
}
}
}
],
"filter": [
{
"range": {
"startedOn": {
"lt": "2018-01-01T00:00:00",
"gte": "2017-01-01T00:00:00"
}
}
}
]
}
}
}
一份文档必须满足三个查询才算匹配成功
- 对名字和姓氏的
match查询有助于计算出相关性分数,因为它们都在查询上下文中执行 - 针对开始日期的
range查询是在筛选上下文中执行的,索引没有为匹配的文档计算分数(针对这个查询的所有文档具有相同的分数1.0)
由于 bool 查询非常常见,因此 NEST 在查询上重载了运算符,以使得 bool 查询的形式更加简洁。前面的 bool 查询可以更加简洁地表示为
searchResponse = client.Search<Project>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.LeadDeveloper.FirstName)
.Query("Russ")
) && q
.Match(m => m
.Field(f => f.LeadDeveloper.LastName)
.Query("Cam")
) && +q
.DateRange(r => r
.Field(f => f.StartedOn)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01))
)
)
);
查看 writing bool queries ,了解有关 bool 查询的更多详细信息和示例
Search response
搜索查询返回的响应是一个 ISearchResponse<T> 对象,其中 T 是在调用搜索方法时传入的泛型参数类型。响应对象有几个属性,其中你最可能使用的是 .Documents ,我们将在下面演示。
Matching documents
获取匹配搜索查询的文档是相当简单的
var searchResponse = client.Search<Project>(s => s
.Query(q => q
.MatchAll()
)
);
var projects = searchResponse.Documents;
.Documents 是对下面这段逻辑的一个方便的速记
searchResponse.HitsMetaData.Hits.Select(h => h.Source);
并且可以从命中集合中检索有关每个命中的其他元数据。下面的示例在使用 highlighting 时检索命中的突出显示
var highlights = searchResponse.HitsMetaData.Hits.Select(h => h
.Highlights
);
NEST - 编写查询的更多相关文章
- NEST - 编写布尔查询
Writing bool queries Version:5.x 英文原文地址:Writing bool queries 在使用查询 DSL 时,编写 bool 查询会很容易把代码变得冗长.举个栗子, ...
- Linux驱动之按键驱动编写(查询方式)
在Linux驱动之LED驱动编写已经详细介绍了一个驱动的编写过程,接着来写一个按键驱动程序,主要是在file_operations结构中添加了一个read函数.还是分以下几步说明 1.查看原理图,确定 ...
- NEST search查询
/// <summary> /// GET /megacorp/employee/_search /// </summary> /// <returns></ ...
- 如何编写更好的SQL查询:终极指南-第一部分
结构化查询语言(SQL)是数据挖掘分析行业不可或缺的一项技能,总的来说,学习这个技能是比较容易的.对于SQL来说,编写查询语句只是第一步,确保查询语句高效并且适合于你的数据库操作工作,才是最重要的.这 ...
- 编写sql查询语句思路
编写查询语句思路/* 1.首先确定最终输出结果的列,包括几个方面:A.首先这些列来自于一个 表.还是多个表,如果是多个表则可能用到多表查询的(等值连接.不等值 连接.外连接.自连接):B.这些列是直接 ...
- 从零开始编写自己的C#框架(19)——Web层后端权限模块
不知不觉本系统写了快三个月了,最近写页面的具体功能时感觉到有点吃力,很多地方如果张嘴来讲的话可以说得很细,很全面,可写成文字的话,就不太会写了,有些地方想讲得清晰的话,得用多几倍的文字+实例+变化中的 ...
- Rafy 框架 - 使用 SqlTree 查询
本文介绍如何使用 Rafy 框架中的 Sql Tree 查询: 除了开发者常用的 Linq 查询,Rafy 框架还提供了 Sql 语法树的方式来进行查询. 这种查询方式下,开发者不需要直接编写真正的 ...
- 关于SubSonic3.0查询或更新时出现System.NullReferenceException异常的处理
在调试程序时,同事发现添加记录时,出现了System.NullReferenceException异常 DictBase dict = new DictBase(); dict.DictCode ...
- Mybatis高级查询之关联查询
learn from:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps 关联查询 准备 关联结果查询(一对一) resul ...
随机推荐
- 计算机中内存、cache和寄存器之间的关系及区别
1. 寄存器是中央处理器内的组成部份.寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令.数据和位址.在中央处理器的控制部件中,包含的寄存 器有指令寄存器(IR)和程序计数器(PC).在中央处理器 ...
- javascript动态的改变checkbox的选中状态
<td> <div class="checkbox"> <label> <input type="checkbox" ...
- ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
背景 老生常谈,为sql当时着迷了,啥都用sql解决.看这个语句,麻烦的. ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN) 简单的说row ...
- 使用Vagrant搭建本地python开发环境
使用Vagrant搭建本地python开发环境 关于vagrant:Vagrant是一个基于Ruby的工具,用于创建和部署虚拟化开发环境,它使用Oracle的开源VirtualBox虚拟化系统也可以使 ...
- python---控制台输出带颜色的文字方法
控制台的展示效果有限,并不能像前端一样炫酷,只能做一些简单的设置,不过站在可读性的角度来看,已经好很多了. 书写格式: ##格式: 设置颜色开始:\033[显示方式;前景色;背景色m ##说明: 前景 ...
- [C][代码实例]整型数组二分排序
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h& ...
- wx.chooseImage
<view>上传图片</view> <view> <view> <button bindtap="getImg">上传图 ...
- js学习——基础知识
数据类型 函数.方法 变量作用域 运算符 条件语句 break和continue typeof 错误(异常) 变量提升 严格模式 JSON void(0) JavaScript ...
- Confluence 6 数据库支持的驱动
数据库 驱动已捆绑? JDBC 驱动 备注 更多信息 PostgreSQL 9.4-1202 JDBC 41 driver download 我们推荐你使用 JDBC 4 的驱动. 如果你希望使用更新 ...
- Linux超级守护进程——xinetd
一 Linux守护进程 Linux 服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程来执行的. ...