Mongo Shell 文档搜索
练习用到的数据:
db.stores.insert(
[
{ _id: 1, name: "Java Hut", description: "Coffee and cakes" },
{ _id: 2, name: "Burger Buns", description: "Gourmet hamburgers" },
{ _id: 3, name: "Coffee Shop", description: "Just coffee" },
{ _id: 4, name: "Clothes Clothes Clothes", description: "Discount clothing" },
{ _id: 5, name: "Java Shopping", description: "Indonesian goods" }
]
)
文字索引
-
MongoDB提供了文本索引来对字符串内容的文本查询搜索,文本索引可以包含值为字符串或者字符串元素数组的任何字段。
-
如果要在集合上执行文档搜索,则集合必须存在文档索引;每一个集合最多只能有一个文档索引,但是文档索引可以覆盖多个字段。
-
例如,在mongo shell执行下面的语句:
db.stores.createIndex( { name: "text", description: "text" } )
会给集合
stores
创建文档索引,该文档索引包含了两个字段name
和description
。
$text运算符
使用 $text
运算符可以对拥有文档索引的集合执行文档搜索操作;
一般查询
$text
可以使用空格和大多数标点作为分隔符对搜索字符串进行标记,并在搜索字符串中对所有这些标记进行逻辑或者操作;
建立了文档索引的字段,如果任意一个字段包含了查询条件中的任意一个术语,那么该文档即是满足查询条件的
例如,下面的语句可以在集合中查找包含"cofee" “java” 和 "shop"列表中任何术语的集合文档:
db.stores.find( { $text: { $search: "java coffee shop" } } )
>>>
[
{ _id: 1, name: "Java Hut", description: "Coffee and cakes" },
{ _id: 3, name: "Coffee Shop", description: "Just coffee" },
{ _id: 5, name: "Java Shopping", description: "Indonesian goods" }
]
准确查询
可以通过将作为查询条件的短语或单个术语包装在双引号中来实现精准查询,如果 $search
的字符串中只包含一个被双引号修饰的短语或单个术语,文本搜索将只匹配文档索引字段的值等于该短语或者单个术语的文档。
db.stores.find( { $text: { $search: "\"coffee shop\"" } } )
>>>
[{ _id: 3, name: "Coffee Shop", description: "Just coffee" },]
期限排除
在需要排除的术语前面加一个 -
符号,则文档搜索将匹配不包含此术语的文档;
db.stores.find( { $text: { $search: "java shop -coffee" } } )
>>>
[
{ _id: 5, name: "Java Shopping", description: "Indonesian goods" }
]
如果查询条件,即 $search
的字符串中只有一个包含否定词的搜索字符串,那么文档索引将不会匹配任何文档,即:
db.stores.find( { $text: { $search: "-coffee" } } )
>>>
None
如果查询字符串中有连字符的词,例如 pre-process
,$text
并不会将连字符视为否定符号,如果要否定带有连字符的术语(以pre-process为例),需要在pre
和 -process
之间插入一个空格,即 pre -process
。
排序
默认情况下,MongoDB查询的返回数据以无序的方式返回,但是文档搜索会为每个文档计算一个相关性分数,即该文档与搜索字符串的相关程度,计算相关性分数需要 $meta 运算符。
db.stores.find(
{ $text: { $search: "java coffee shop" } },
{ score: { $meta: "textScore" } }
).sort( { score: -1 } )
>>>
[
{ _id: 3, name: "Coffee Shop", description: "Just coffee", "score":2.25},
{ _id: 5, name: "Java Shopping", description: "Indonesian goods", "score":1.5 },
{ _id: 1, name: "Java Hut", description: "Coffee and cakes", "score":1.5 }
]
在计算相关性分数的时候,*** m e t a ∗ ∗ ∗ 的 值 固 定 为 " t e x t S c o r e " , 具 体 用 法 可 以 看 [ meta***的值固定为 "textScore",具体用法可以看 [ meta∗∗∗的值固定为"textScore",具体用法可以看[meta](https://www.mongodb.com/docs/manual/reference/operator/aggregation/meta/#mongodb-expression-exp.-meta);上面的查询语句是find语句结束后,查询的信息里面多了一个字段score,然后再根据score排下序。
$text的限制
$text操作符的使用有一些限制条件:
- 一个查询中最多指定一个$text表达式;
- t e x t 不 能 出 现 在 text不能出现在 text不能出现在nor表达式中;
- t e x t 不 能 出 现 在 text不能出现在 text不能出现在eleMatch表达式中;
- 如果在 o r 表 达 式 中 使 用 or表达式中使用 or表达式中使用text,则$or的数组中每一个子句都必须被索引
- …
聚合管道
文档搜索也可以用在聚合管道中
限制条件
除了 t e x t 本 身 的 限 制 , 在 聚 合 管 道 使 用 text本身的限制,在聚合管道使用 text本身的限制,在聚合管道使用text也有一些额外的限制:
- 包含 t e x t 的 语 句 必 须 是 text的语句必须是 text的语句必须是match阶段的第一个阶段;
- $text在管道的阶段中只能出现一次;
- t e x t 不 能 出 现 在 text不能出现在 text不能出现在or和$not运算符的表达式中;
- 默认情况下,文本搜索不会按照顺序返回文档,但是可以在 s o r t 阶 段 通 过 sort阶段通过 sort阶段通过meta聚合表达式使文档有序返回。
文字分数
t
e
x
t
操
作
符
为
搜
索
的
每
一
个
文
档
提
供
一
个
分
数
,
分
数
表
示
文
档
与
搜
索
文
本
的
相
关
程
度
,
这
个
分
数
可
用
于
text操作符为搜索的每一个文档提供一个分数,分数表示文档与搜索文本的相关程度,这个分数可用于
text操作符为搜索的每一个文档提供一个分数,分数表示文档与搜索文本的相关程度,这个分数可用于sort阶段进行排序,分数的计算: {$meta: 'textScore'}
db.articles.aggregate(
[
{ $match: { $text: { $search: "cake tea" } } },
{ $sort: { score: { $meta: "textScore" } } },
{ $project: { title: 1, _id: 0 } }
]
)
还可以进行文字分数匹配,即返回相关性高于某数字的文档:
db.articles.aggregate(
[
{ $match: { $text: { $search: "cake tea" } } },
{ $project: { title: 1, _id: 0, score: { $meta: "textScore" } } },
{ $match: { score: { $gt: 1.0 } } }
]
)
指定文本搜索的语言:
db.articles.aggregate(
[
{ $match: { $text: { $search: "saber -claro", $language: "es" } } },
{ $group: { _id: null, views: { $sum: "$views" } } }
]
)