使用MongoDB进行方面搜索

Fir*_*ari 13 mongodb faceted-search

我正在考虑将MongoDB用于我的下一个项目.此应用程序的核心要求之一是提供方面搜索.有没有人尝试使用MongoDB实现方面搜索?

我有一个产品型号,具有各种属性,如大小,颜色,品牌等.在搜索产品时,此Rails应用程序应在侧栏上显示构面过滤器.Facet过滤器看起来像这样:

Size:
XXS (34)
XS (22)
S (23)
M (37)
L (19)
XL (29)

Color:
Black (32)
Blue (87)
Green (14)
Red (21)
White (43)

Brand:
Brand 1 (43)
Brand 2 (27)
Run Code Online (Sandbox Code Playgroud)

Sam*_*cía 19

我认为使用Apache Solr或ElasticSearch可以获得更大的灵活性和性能,但使用聚合框架支持这一点.

使用MongoDB的主要问题是你需要查询N次:首先获得匹配的结果,然后每组一次; 使用全文搜索引擎时,您可以在一个查询中获取所有内容.

//'tags' filter simulates the search
//this query gets the products
db.products.find({tags: {$all: ["tag1", "tag2"]}})

//this query gets the size facet
db.products.aggregate(
    {$match: {tags: {$all: ["tag1", "tag2"]}}}, 
    {$group: {_id: "$size"}, count: {$sum:1}}, 
    {$sort: {count:-1}}
)

//this query gets the color facet
db.products.aggregate(
    {$match: {tags: {$all: ["tag1", "tag2"]}}}, 
    {$group: {_id: "$color"}, count: {$sum:1}}, 
    {$sort: {count:-1}}
)

//this query gets the brand facet
db.products.aggregate(
    {$match: {tags: {$all: ["tag1", "tag2"]}}}, 
    {$group: {_id: "$brand"}, count: {$sum:1}}, 
    {$sort: {count:-1}}
)
Run Code Online (Sandbox Code Playgroud)

用户使用构面过滤搜索后,您必须添加此过滤器以查询谓词并匹配谓词,如下所示.

//user clicks on "Brand 1" facet
db.products.find({tags: {$all: ["tag1", "tag2"]}, brand: "Brand 1"})

db.products.aggregate(
    {$match: {tags: {$all: ["tag1", "tag2"]}}, brand: "Brand 1"}, 
    {$group: {_id: "$size"}, count: {$sum:1}}, 
    {$sort: {count:-1}}
)

db.products.aggregate(
    {$match: {tags: {$all: ["tag1", "tag2"]}}, brand: "Brand 1"}, 
    {$group: {_id: "$color"}, count: {$sum:1}}, 
    {$sort: {count:-1}}
)

db.products.aggregate(
    {$match: {tags: {$all: ["tag1", "tag2"]}}, brand: "Brand 1"}, 
    {$group: {_id: "$brand"}, count: {$sum:1}}, 
    {$sort: {count:-1}}
)
Run Code Online (Sandbox Code Playgroud)


Rah*_*hul 7

Mongodb 3.4引入了分面搜索

$ facet阶段允许您创建多面聚合,这些聚合可在单个聚合阶段内跨多个维度或方面表征数据.多面聚合提供多个过滤器和分类,以指导数据浏览和分析.

输入文档仅传递给$ facet阶段一次.

现在,您不需要查询N次以检索N个组上的聚合.

$ facet在同一组输入文档上启用各种聚合,而无需多次检索输入文档.

OP用例的示例查询类似于

db.products.aggregate( [
  {
    $facet: {
      "categorizedByColor": [
        { $match: { color: { $exists: 1 } } },
        {
          $bucket: {
            groupBy: "$color",
            default: "Other",
            output: {
              "count": { $sum: 1 }
            }
          }
        }
      ],
      "categorizedBySize": [
        { $match: { size: { $exists: 1 } } },
        {
          $bucket: {
            groupBy: "$size",
            default: "Other",
            output: {
              "count": { $sum: 1 }
            }
          }
        }
      ],
      "categorizedByBrand": [
        { $match: { brand: { $exists: 1 } } },
        {
          $bucket: {
            groupBy: "$brand",
            default: "Other",
            output: {
              "count": { $sum: 1 }
            }
          }
        }
      ]
    }
  }
])
Run Code Online (Sandbox Code Playgroud)

  • mongodb 中有没有一种方法可以只运行一个查询来获取文档和相关的方面? (2认同)