词项查询 #
Easysearch 在搜索数据时支持两种类型的查询:词项 (term) 查询和全文查询。
下表显示了它们之间的差异:
词项查询 | 全文检索 | |
---|---|---|
描述 | term 查询回应与查询匹配的文档。 | 全文查询回应文档与查询的匹配程度。 |
分词 | 搜索 term 是不分词的。这意味着 term 查询按原样搜索您的 term。 | 搜索 term 由索引时用于文档指定字段的分词器进行分词。这意味着您的搜索词将经历与文档字段相同的分词过程。 |
相关性 | Term 级查询只返回匹配的文档,而不根据相关性得分对其进行排序。他们仍然计算相关性得分,但该得分对于返回的所有文档都是相同的。 | 全文查询计算每个匹配的相关性得分,并按相关性的降序对结果进行排序。 |
应用场景 | 当您希望匹配数字、日期、 tag 等精确值,并且不需要按相关性对匹配项进行排序时,请使用术语级查询。 | 在考虑大小写和词干变体等因素后,使用全文查询来匹配文本字段并按相关性排序。 |
Easysearch 使用名为 Okapi BM25 的概率排名框架来计算相关性得分。要了解更多关于 Okapi BM25 的信息,请参阅 维基百科.
假设您在 Easysearch 集群中索引了莎士比亚全集。我们使用 term 查询在 text_entry
字段中搜索短语 “To be,or not be”:
GET shakespeare/_search
{
"query": {
"term": {
"text_entry": "To be, or not to be"
}
}
}
响应示例 #
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
我们没有找回任何匹配( hits
)。这是因为 term “To be, or not to be”是在倒排索引中按字面搜索的,其中只存储文本字段的分词后的值。Term 查询不适合搜索分词的文本字段,因为它们通常会产生意外的结果。使用文本数据时,仅对仅映射为 keyword 的字段使用 term 查询。
使用全文查询:
GET shakespeare/_search
{
"query": {
"match": {
"text_entry": "To be, or not to be"
}
}
}
搜索查询 “To be,or not be” 被分析并标记为一个标记数组,就像文档的 text_entry
字段一样。全文查询在搜索查询和所有文档的 text_entry
字段之间执行标记的交集,然后根据相关性得分对结果进行排序:
响应示例 #
{
"took" : 19,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : 17.419369,
"hits" : [
{
"_index" : "shakespeare",
"_type" : "_doc",
"_id" : "34229",
"_score" : 17.419369,
"_source" : {
"type" : "line",
"line_id" : 34230,
"play_name" : "Hamlet",
"speech_number" : 19,
"line_number" : "3.1.64",
"speaker" : "HAMLET",
"text_entry" : "To be, or not to be: that is the question:"
}
},
{
"_index" : "shakespeare",
"_type" : "_doc",
"_id" : "109930",
"_score" : 14.883024,
"_source" : {
"type" : "line",
"line_id" : 109931,
"play_name" : "A Winters Tale",
"speech_number" : 23,
"line_number" : "4.4.153",
"speaker" : "PERDITA",
"text_entry" : "Not like a corse; or if, not to be buried,"
}
},
{
"_index" : "shakespeare",
"_type" : "_doc",
"_id" : "103117",
"_score" : 14.782743,
"_source" : {
"type" : "line",
"line_id" : 103118,
"play_name" : "Twelfth Night",
"speech_number" : 53,
"line_number" : "1.3.95",
"speaker" : "SIR ANDREW",
"text_entry" : "will not be seen; or if she be, its four to one"
}
}
]
}
}
...
有关所有全文查询的列表,请参见 全文查询。
如果您想在 speaker 字段中查询类似 “HAMLET” 的准确术语,并且不需要根据相关性得分对结果进行排序,则 term 查询更有效:
GET shakespeare/_search
{
"query": {
"term": {
"speaker": "HAMLET"
}
}
}
响应示例 #
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1582,
"relation" : "eq"
},
"max_score" : 4.2540946,
"hits" : [
{
"_index" : "shakespeare",
"_type" : "_doc",
"_id" : "32700",
"_score" : 4.2540946,
"_source" : {
"type" : "line",
"line_id" : 32701,
"play_name" : "Hamlet",
"speech_number" : 9,
"line_number" : "1.2.66",
"speaker" : "HAMLET",
"text_entry" : "[Aside] A little more than kin, and less than kind."
}
},
{
"_index" : "shakespeare",
"_type" : "_doc",
"_id" : "32702",
"_score" : 4.2540946,
"_source" : {
"type" : "line",
"line_id" : 32703,
"play_name" : "Hamlet",
"speech_number" : 11,
"line_number" : "1.2.68",
"speaker" : "HAMLET",
"text_entry" : "Not so, my lord; I am too much i' the sun."
}
},
{
"_index" : "shakespeare",
"_type" : "_doc",
"_id" : "32709",
"_score" : 4.2540946,
"_source" : {
"type" : "line",
"line_id" : 32710,
"play_name" : "Hamlet",
"speech_number" : 13,
"line_number" : "1.2.75",
"speaker" : "HAMLET",
"text_entry" : "Ay, madam, it is common."
}
}
]
}
}
...
Term 查询精确匹配。所以,如果你搜索 “Hamlet” ,你不会得到任何匹配,因为 “HAMLET” 是一个 keyword 字段,它是按字面意思存储在 Easysearch 中,而不是以分词的形式存储的。 搜索查询“HAMLET”也按字面搜索。因此,要在该字段上获得匹配,我们需要输入完全相同的字符。
Term 查询 #
term
查询在字段中搜索精确的 term。
GET shakespeare/_search
{
"query": {
"term": {
"line_id": {
"value": "61809"
}
}
}
}
Terms 查询 #
terms
查询在同一字段中搜索多个 term。
GET shakespeare/_search
{
"query": {
"terms": {
"line_id": [
"61809",
"61810"
]
}
}
}
你会得到符合任何 term 的文档。
IDs #
ids
查询搜索一个或多个文档 ID 值。
GET shakespeare/_search
{
"query": {
"ids": {
"values": [
34229,
91296
]
}
}
}
Range #
范围
查询搜索字段中的值范围。
要搜索 line_id
值 >= 10 and <= 20 的文档,请执行以下操作:
GET shakespeare/_search
{
"query": {
"range": {
"line_id": {
"gte": 10,
"lte": 20
}
}
}
}
参数 | 行为 |
---|---|
gte | 大于等于。 |
gt | 大于。 |
lte | 小于等于。 |
lt | 小于。 |
假设您有一个 products
索引,并且希望查找 2023 年添加的所有产品:
GET products/_search
{
"query": {
"range": {
"created": {
"gte": "2023/01/01",
"lte": "2023/12/31"
}
}
}
}
使用基本数学表达式指定相对日期。
从指定日期减去 1 年零 1 天:
GET products/_search
{
"query": {
"range": {
"created": {
"gte": "2023/01/01||-1y-1d"
}
}
}
}
我们指定的第一个日期是定位日期或日期数学的起点。添加两个拖曳管道符号。然后你可以加一天( +1d
)或减去两周( -2w
)。此数学表达式与您指定的定位日期相关。
您还可以通过在日期或时间单位中添加正斜杠来舍入日期。
要查找上一年添加并按月份四舍五入的产品:
GET products/_search
{
"query": {
"range": {
"created": {
"gte": "now-1y/M"
}
}
}
}
关键字 now
指向当前日期和时间。
前缀 Prefix #
prefix
查询搜索以特定前缀开头的 term。
GET shakespeare/_search
{
"query": {
"prefix": {
"speaker": "KING"
}
}
}
是否存在 Exists #
exists
查询搜索包含特定字段的文档。
GET shakespeare/_search
{
"query": {
"exists": {
"field": "speaker"
}
}
}
通配符 Wildcards #
通配符查询搜索与通配符模式匹配的 term。
特征 | 行为 |
---|---|
* | 匹配所有有效值。 |
? | 匹配单个有效值。 |
要搜索以 H
开头并以 Y
结尾的 term :
GET shakespeare/_search
{
"query": {
"wildcard": {
"speaker": {
"value": "H*Y"
}
}
}
}
如果我们将 *
更改为 ?
,我们得不到匹配,因为 ?
代表单个字符。
通配符查询往往很慢,因为它们需要遍历大量术语。避免在查询的开头放置通配符,因为这可能是一个资源和时间都非常昂贵的操作。
正则 Regex #
使用 regex
查询搜索与正则表达式匹配的 term。
此正则表达式匹配任何单个大写或小写字母:
GET shakespeare/_search
{
"query": {
"regexp": {
"play_name": "H[a-zA-Z]+mlet"
}
}
}
正则表达式应用于字段中的 term ,而不是字段的整个值。
正则表达式的效率在很大程度上取决于您编写的模式。确保使用前缀或后缀编写 regex
查询以提高性能。