搜索语法


概述

云 API 允许你在某个用户帐户内搜索笔记,这是一项强大的搜索功能。本文档给出完整的搜索语法。如果需要学习如何使用搜索功能,请参考 搜索笔记 章节.

印象笔记将所有对笔记的搜索转化成基于文本的简单字符串形式。该内部搜索格式用于 SavedSearch 查询,有能力的用户也可以直接使用。印象笔记服务以及所有客户端都实现了该搜索语法,因此,在所有系统上,相同的搜索必然能得到相同的结果。

根据简单的检索词列表从一个笔记本(或“所有笔记本”)中寻找匹配,这是印象笔记的搜索语法。默认情况下,搜索结果是单个检索词所匹配的笔记的交集。但是,当搜索中包含 “ any: ” 修饰符时,搜索结果是这些单独匹配结果的并集,只要笔记匹配其中任一个检索词,就能被返回。显然,如果仅有一个检索词,那么,无论是否包含 “ any: ” 修饰符,得到的结果都一样。

字符串匹配是大小写不敏感的,多个空格会作为一个空格处理。

搜索语法还包含形如“修饰符:参数”的一套高级搜索表达式。一条笔记符合满足合适条件的时候就能匹配该表达式。检索词的比较方式视修饰符的类型而定,因此日期与字符串的比较方式可能会不同。

可以在任何检索词前面加一个负号“-”对条件取反。这意味着只有不满足该条件的笔记才会被匹配。在搜索中每个检索词可以是下面其中一个:

检索词

这部分描述了搜索语法是如何来解释搜索表达式中的检索词的。

范围修饰符

notebook:[nb name] - 将匹配指定名字的笔记本中的笔记。它必须是搜索中的第一个词。名字匹配是大小写敏感的。因为笔记的笔记本属性具有排他性,搜索的时候最多只能指定一个笔记本。如果搜索的时候未指定笔记本,该搜索将遍历用户的所有活动笔记本。指定的笔记本将不会被“any”操作符产生的“union”行为包含。例如:

  • notebook:"Bob's first notebook"
    • 匹配该笔记本里面的所有笔记。
  • notebook:"Hot Stuff" any: mexican italian
    • 匹配笔记本“Hot Stuff”里面同时包含“mexican”和“italian”两个单词的笔记。

any: - 如果该表达式出现在搜索表达式的开始处(如果有“notebook”,则应在其之后),那么将会返回满足任何其他检索词条件的笔记。如果没有“any”,那么就采用默认的行为:笔记必须满足所有搜索条件。该表达式不能加负号取反。

按文字匹配检索词

如果没有发现高级修饰符,检索词将会按照普通文本搜索在笔记里面进行匹配。单词或者用引号括起来的短语必须精确的匹配笔记内容、标题、标签或者智能识别索引里面的一个单词或者短语。笔记内容里面的单词通过空白字符或者标点符号进行分词。可以在搜索关键词结尾加上通配符,从而来匹配某个单词的起始部分。搜索是大小写不敏感的。(由于服务扩展性的原因,通配符只允许在检索词的结尾出现,而不能在开始和中间出现。)在引号括起来的短语或者笔记中,多个空白字符和/或标点符号将会被当做单个空格来匹配。在括起来的短语中可以用反斜杠“\”来转义引号。例如:

  • potato
    • 匹配: "Sweet Potato Pie"
    • 不匹配: "Mash four potatoes together"
  • Ever*
    • 匹配: "Evernote Corporation"
    • 不匹配: "forevernote"
  • "San Francisco"
    • 匹配: "The hills of San Francisco"
    • 不匹配: "San Andreas fault near Francisco winery"
  • -potato
    • 匹配: "Mash four potatoes together"
    • 不匹配: "Sweet Potato Pie"
  • ham
    • 匹配: "green eggs&ham."
  • "eggs ham"
    • 匹配: "green eggs&ham."

标点符号被用来对搜索表达式和文档进行分词,但是在进行文本匹配的时候会被忽略。一个使用引号括起来的搜索的行为应该与如下操作在搜索表达式和目标笔记上都执行的效果一致:

  1. 所有XML标识都从文档中移除,只留下由可见字符组成的一个字符串
  2. 这个字符串被一个或多个空白字符和/或标点符号分割成一个单词列表
  3. 列表里面的每个单词的大小写被规范化
  4. 检索词中单词列表必须与笔记中转换后的具有相同顺序的单词列表进行匹配

例如,如果用户在下面这个 ENML 文档中搜索短语 "Spatula! City! For Bargains...":

该语法将搜索短语转换成规范化后的单词列表:

[ "spatula", "city", "for", "bargains" ]

笔记文档转换为:
[ "come", "down", "to", "spatula", "city", "for", "bargains", "on", "spatulas" ]

该搜索将会匹配,因为从笔记文档中提取出来的单词列表中可以发现由目标短语转换后的单词列表。(同样的结果也可以通过其他方法实现,而不必将每条笔记逐字的转换成单词列表,但是它给了我们从主流搜索引擎如 Google 和 MS 上看到的预期的行为。)

匹配笔记核心属性

tag:[tag name] - 满足如下条件的笔记将会被匹配:拥有与指定名字(单词或者用引号括起来的短语)完全匹配的标签。这里不要求大小写完全匹配。指定的标签名字可以用通配符结束,以匹配某个标签的起始部分。该模式将从标签完整名字的开始进行匹配,标点符号也会被包含在内。即标签和搜索字符串不会被空白字符和/或标点符号分成单词列表。该表达式可以被多次使用以指定笔记必须匹配的所有标本。例如:

  • tag:cooking
    • 匹配任何含有“cooking”标签的笔记
  • tag:cook*
    • 匹配任何含有以“cook”开始的标签的笔记
  • -tag:cook*
    • 匹配任何不含以“cook”开始的标签的笔记
  • tag:*
    • 匹配含有至少一个标签的任何笔记
  • -tag:*
    • 匹配所有没有标签的笔记

intitle:[literal] - 如果标题含有与指定的单词或者短语,该笔记将会被匹配。该语法在一个查询中可以多次使用。例如:

  • intitle:chicken
    • 匹配标题中含有“chicken”单词的笔记
  • intitle:"tale of two"
    • 如果标题含有“tale of two” 或者 “tale of two”, 甚至”Tale of , two“, 都将会被匹配
  • -intitle:beef
    • 匹配标题里面不含“beef”单词的笔记

created:[datetime] - 如果笔记有一个与之相同或者比提供的时间离现在更近的“created”时间戳将会被匹配。(参考章节 C.2 获取关于合法日期格式的更多信息。) 例如:

  • created:20070704
    • 基于客户端的时区设置, 匹配创建日期为2007年7月4号或者之后的笔记。
  • created:20070704T090000
    • 基于客户端的时区设置, 匹配创建时间为2007年7月4号上午9点或者之后的笔记。
  • created:20070704T150000Z
    • 匹配创建时间为GMT时间2007年7月4号下午3点或者之后的笔记。
  • -created:20070704
    • 基于客户端的时区设置, 匹配创建时间早于2007年7月4号的笔记。
  • created:day-1
    • 匹配昨天或者今天创建的笔记。
  • -created:day
    • 匹配今天之前创建的笔记。
  • created:day-1 -created:day
    • 只匹配昨天创建的笔记。
  • created:day-30
    • 匹配最近30天内(含今天)创建的笔记。
  • created:week
    • 本日历周内创建的笔记(周日-周六)。
  • -created:month
    • 在本月之前创建的笔记。
  • created:year-1
    • 匹配去年或者今天创建的笔记。

updated:[datetime] - 如果笔记有一个与之相同或者比提供的时间离现在更近的“updated”时间戳将会被匹配。(参考章节 C.2 获取关于合法日期格式的更多信息。)

resource:[MIME type string] - 如果笔记含有指定的 MIME 类型的资源将会被匹配,例如:

  • resource:image/gif
    • 匹配的笔记至少含有一个 image/gif 类型的资源
  • resource:audio/*
    • 匹配的笔记至少含有一个音频资源
  • -resource:image/*
    • 匹配的笔记不含图片资源
  • resource:application/vnd.evernote.ink
    • 匹配的笔记含有一个或者更多的 ink 资源
属性匹配

搜素表达式还可以包含用来匹配数据模型中定义的任何属性的检索词。这些属性定义在 Types.thrift 中的 NoteAttributs 和 ResourceAttributes 结构体里面。如果 NoteAtrtributes 含有指定名字的属性,将会根据笔记的属性进行匹配,否则如果存在指定名字的资源属性,则尝试根据资源的属性进行匹配。该匹配操作基于属性的类型来执行。

字符串属性使用上述标准的字符串匹配算法进行比较(大小写不敏感,规范化空白字符,参数结尾可选的通配符)。
Datetime attributes will be matched in the same manner as "created" and "updated", above. Datetime 属性会使用前面提到的 “created” 和 “updated” 中的方式来进行匹配。

布尔属性将根据参数的“true”和“false”进行比较。一个布尔属性如果设置了任何值都会匹配通配符(“*”)。

Double双精度值表达式将会匹配属性值大于等于指定参数的笔记(参考“latitude”例子)。Double 的比较是根据数值而不是字符来比较的,因此参数“99.9”小于“100”。Double 属性设置了任何值都会匹配通配符(“*”)。

subjectDate:[datetime] - 如果笔记的“subjectDate”属性等于或者晚于指定的 datetime 参数则被匹配。

latitude:[double] - 如果笔记设置了一个大于等于指定参数的“latitude”属性则被匹配。例如:

  • latitude:37 -latitude:38
    • 如果笔记有 latitude 属性,并且值大于等于37,同时小于38,则被匹配。(即 37 <= latitude < 38)

longitude:[double] - 匹配”longitude“属性值大于等于指定参数的笔记。

altitude:[double] - 匹配“altitude”属性值大于等于指定参数的笔记。

author:[string] - 匹配“author”属性值与指定参数相同的笔记。例如:

  • author:"robert parker"
  • author:robert*
  • -author:*
    • 匹配没有设置“author”属性的笔记

source:[string] - 匹配来自某个应用或者数据源的笔记。不是所有笔记都含有“source”属性。标准的 source 属性查询包括:

  • source:web.clip
    • 匹配使用印象笔记·剪藏剪辑网页生成的笔记。
  • source:mail.clip
    • 匹配来自本地邮件客户端剪切生成的笔记。
  • source:mail.smtp
    • 匹配通过电子邮件网关发送给印象笔记服务生成的笔记。
  • source:mobile.ios
    • 匹配使用某种形式的 iOS 客户端创建的笔记。
  • source:mobile.android
    • 匹配使用某种形式的 Android 客户端创建的笔记。
  • source:mobile.*
    • 匹配使用某种形式的移动客户端创建的笔记。

sourceApplication:[string] - 匹配设置了应用来源属性并满足条件的笔记。该字符串属性不保证有标准结构。标准的 sourceApplication 属性查询包括:

  • sourceApplication:food.*
    • 查找使用印象笔记·食记创建的笔记。
  • sourceApplication:hello.*
    • 查找使用印象笔记·人脉创建的笔记。
  • sourceApplication:skitch.*
    • 查找使用印象笔记·圈点创建的笔记。

contentClass:[string] - 匹配设置了 contentClass 属性并满足参数指定参数值的笔记。例如:

  • contentClass:evernote.food.meal
    • 匹配所有印象笔记·食记创建的笔记。
  • contentClass:evernote.hello.*
    • 匹配所有印象笔记·人脉创建的笔记。

placeName:[string] - 匹配设置了 placeName 属性并匹配指定参数值的笔记。例如:

  • placeName:home
    • 匹配设置了 placeName 属性并且属性值为“home”的笔记。

applicationData:[string] - 如果笔记的 applicationData map 的某个 key 与指定参数匹配,则该笔记将被匹配。这允许查找所有设置了某个应用特有 metadata 的笔记。例如:

  • applicationData:myapp
    • 笔记的applicationData map 中含有“myapp”的 entry 则被匹配。
  • applicationData:*
    • 笔记的 applicationData map 中至少含有一个 entry 则被匹配。

recoType:[string] - 如果笔记的资源包含了智能识别数据并指定了所识别的文档的类型,且与指定的参数匹配,则该笔记将被匹配。如果一个资源设置了该属性,它将取以下值中的一个:“printed”,“speech”,“handwritten”,“picture”,或者“unknown”。例如:

  • recoType:handwritten
    • 如果笔记至少有一个被识别为手写的资源则被匹配。Matches notes with at least one resource that was recognized as handwritten
  • recoType:*
    • 如果笔记至少有一个设置了智能识别索引数据的资源则被匹配。

高级内容匹配

下面的检索词被表达成属性,但是并不会与 NoteAttribute 数据模型中的某个属性有关系。事实上,它对笔记的内容进行一些高级查询匹配。这些并不会与笔记里面的标准的单词进行匹配,而是与 ENML 文档里面嵌入的特别元素进行匹配。

todo:[true|false|*] - 如果参数设置为“true”,将会匹配含有当前已选中的 ToDo 复选框的笔记。如果参数设置为“false”,将会匹配含有当前未选中的 ToDo 复选框的笔记。如果参数是“*”,则含有任何 ToDo 复选框的笔记都会被匹配。

  • -todo:false todo:true
    • 匹配所有 ToDO 事项都已经完成的笔记。

encryption: - 匹配含有加密部分的笔记。

日期/时间参数

很多表达式(例如“created:...”)带有被解释成日期或者日期和时间的参数。日期被转换成国际标准时间来和笔记的时间戳进行比较。搜索语法包含两种时间日期表达式,一种指定绝对的时间(包括年月日等),另一种根据当前的日/星期/月/年来指定相对时间。前一种可以在确定时间范围内搜索,但是后一种在一些保存的查询中特别有用,如返回最近7天内的笔记。

绝对日期时间参数

绝对日期时间通过使用 ISO 8601( http://en.wikipedia.org/wiki/ISO_8601 )描述的压缩格式来指定。一个绝对日期时间必须满足下面三种格式之一:
yyyyMMdd - 用来指定不需要时间字段的日期。等价于“yyyyMMddT000000”。该日期在与笔记内部保存的国际标准时间戳进行比较之前,将会根据客户端期望的时区转换成国际标准时间。例如“20071031”等价于基于客户端时区的2007年10月31号0点。
yyyyMMdd'T'HHmmss - 指定带时间字段的日期。该日期和时间在与笔记内部保存的国际标准时间戳进行比较之前,将会根据客户端期望的时区转换成国际标准时间。例如“20071031T093000”等价于基于客户端时区的2007年10月31号9:30am。
yyyyMMdd'T'HHmmss'Z' - 指定UTC (又叫做“GMT”或者“Zulu”) 时间. 该日期时间可以直接作为国际标准时间与笔记进行比较,而同时忽略客户端本身的时区设置。例如“20071031T153000Z”被解释为国际标准时间2007年10月31号3:30pm。

相对日期时间参数

相对时间参数将根据客户端得到的当前“天”,“星期”,“月”或者“年”的起始时间来计算。他们可以包含一个整型偏移量来指定之前的某天/星期/月/年。如果没有指定偏移量,则解释成当前天/星期/月/年的起始时间。下面的例子解释了每个表达式是如何计算的(假设当前时间为:2007年10月31号 13:30 56 星期三):

  • day - 计算为: 2007年10月31号 00:00:00
  • day-1 - 计算为:2007年10月30号 00:00:00 星期二
  • day-14 - 计算为:2007年10月17号 00:00:00 星期三
  • week - 计算为: 2007年10月28号 00:00:00 星期天
  • week-2 - 计算为: 2007年10月14号 00:00:00 星期天
  • month - 计算为: 2007年10月1号 00:00:00 星期一
  • month-1 - 计算为: 2007年9月1号 00:00:00 星期一
  • year - 计算为: 2007年1月1号 00:00:00 星期一
  • year-1 - 计算为: 2006年1月1号 00:00:00 星期天

例子

查找包含“chicken”,有“cooking”标签并且创建于今年的笔记:

chicken tag:cooking created:year

查找有“cooking”标签,但没有“mexican”标签,并且含有单词“beef”而不含单词“carrots”的笔记:

tag:cooking -tag:mexican beef -carrots

查找“Travel”笔记本中标题含有“San Francisco”的笔记:

notebook:Travel intitle:"San Francisco"

查找含有“San Francisco”短语或者“SFO”标签的笔记:

any: "San Francisco" tag:SFO

查找 Sunnyvale 地区的图片笔记:

resource:image/* latitude:37 -latitude:38 longitude:-123 -longitude:-122

查找最近两星期内编辑过的没有标签的音频笔记

-tag:* resource:audio/* updated:week-1

形式化搜索语法

下面的语法采用EBNF 范式描述。该语法假定递归下降语法分析将会“贪婪”的处理任何歧义。语法分析的输出是一系列的检索词和操作符;分隔符将会被忽略。不满足该语法的搜索表达式的语法分析结果是未定义的。