Php 如何创建跨大型动态数据集计算标记的性能系统
概述 我有一个Php 如何创建跨大型动态数据集计算标记的性能系统,php,mongodb,design-patterns,database-design,architecture,Php,Mongodb,Design Patterns,Database Design,Architecture,概述 我有一个iOS应用程序,人们可以通过标签进行搜索一些标签是预定义的,一些是用户定义的 当用户编写他/她想要搜索的标记时,我想显示一行,显示那些标记可用的结果数(参见示例搜索图片) 注意:#练习或#例行程序是父母标签,这意味着此人总是先使用其中一个标签 我正在使用PHP和MongoDB服务器端。 我想创建一个每小时计数一次的带有标记的文件,这样所有客户机都可以获取它并将资源消耗降至最低 考虑到被操纵的信息是用户控制的标签,列表将随着时间的推移而大大扩展 挑战 我不知道什么是考虑问题的最佳方
iOS
应用程序,人们可以通过标签进行搜索
一些标签是预定义的,一些是用户定义的
当用户编写他/她想要搜索的标记时,我想显示一行,显示那些标记可用的结果数(参见示例搜索图片)
注意:#练习
或#例行程序
是父母标签
,这意味着此人总是先使用其中一个标签
我正在使用PHP
和MongoDB
服务器端。
我想创建一个每小时计数一次的带有标记的文件,这样所有客户机都可以获取它并将资源消耗降至最低
考虑到被操纵的信息是用户控制的标签
,列表将随着时间的推移而大大扩展
挑战
- 我不知道什么是考虑问题的最佳方法
创建、操作和存储此类文件的性能和开销
名单
我的第一个想法是创建一个2d数组
(见图),它将存储我的所有值。然后将其转换为JSON,以便将其存储到MongoDB中
但这种方法将使我获取所有标记并将它们加载到内存中,以执行任何+1或-1操作。因此,我认为这可能不是最好的
所有操作都将在插入、更新和删除每个元素时进行。因此将有相当大的RAM
开销
我的第二个想法是创建一个文档
,在那里我存储所有使用的标签
,并每小时进行计数查询,以生成客户使用的列表
这意味着每次删除、更新和插入时,都要检查标签是否存在于该文档中,并根据条件创建或删除标签或不执行任何操作
每小时,获取所有标记,生成一个包含所有标记组合的数组。根据所有标记组合查询数据库,计算返回的结果数并创建文件
考虑到我使用的是MongoDB
,而不是MySQL
,我认为这种方法可能会更好。但我仍然不确定它的性能
有没有人做过类似的系统,可以就更好的方法提出建议
搜索示例图片
2d阵列
由于问题很长,我将列出我在反复阅读问题几遍后所做的一些假设:
人们可以输入n个标签进行搜索
标记是预定义的或用户定义的
标签将随着时间的推移而显著增加
我们需要一组给定标记的文档总数。如果#tag1有10个,而#tag2有13个,那么我们大约有23个文档(考虑到有些文档可能同时有两个标记)
我有一些关于方法的建议:
您已经开始这样想了,但计划将读和写分开。如果有人将文档标记为#cost,请立即继续写,但不要在所有读取中都提供该信息。(这将返回到每小时运行的作业。)
您可以立即向标记文档的用户提供反馈。我听说YouTube就是这么做的。你喜欢YouTube上的内容,它会立即增加数字,即使写的内容还没有提交。这个想法是你立即给用户一些东西——即使它不是完全准确的
(2)认为数字只是“足够好”。搜索#胸部和#常规。。。假设返回100结果。请随意显示98或99。在球场上。换句话说,只要用户能够感觉到有多少结果,就可以不立即说明+1和-1
考虑运行一个将数据移出Mongo的作业。您可以让Mongo运行map/reduce查询,该查询输出到Mongo中的集合。然后你可以把它放在像Redis这样的东西里来服务数据。或者我想你可以把它放在蒙戈
我不确定我会创造出所有可能的组合。这将很快失去控制-尤其是如果人们可以创建自己的标签。相反,只需创建一个简单的数据结构,其中包含带有计数的搜索项。[“胸部”,100],“常规”,543],“三头肌”,12]
可以指出的是,如果一个文档有多个标记,我们将计算它两次。这是真的,但我会主张简单化,不去管它。如果您愿意在计数方面牺牲一点精度,那么您的代码将更易于维护和执行
更新:重写此概念以避免对MySQL示例的混淆
正如原始答案中所述,我是蒙哥达无知者。因此,我将简单地解释这个概念
也许仍然有一种方法可以获得性能良好的准确计数。这是基于这样的假设,即您希望标记列表(包含所有请求的标记的所有文档)的交集
1) 创建包含3个字段的新集合(标记\查询\缓存):
- 标记\主键:主键-查询中所有标记的字符串
- tags_count:包含tags_列表中所有标记的文档数
- 标签列表:标签数组-标签键中的所有标签(应该是标签的索引)
2) 更新|添加|删除原始收藏中的文档时:
- 识别文档中已更改(添加或删除)的所有标记
- 删除标记\u查询\u cach中的所有文档
> db.performant.find()
{ "_id" : ObjectId("522bf7166094a4e72db22827"), "name" : "abc", "tags" : [ "chest", "bicep", "tricep" ] }
{ "_id" : ObjectId("522bf7406094a4e72db22828"), "name" : "def", "tags" : [ "routine", "trufala", "tricep" ] }
{ "_id" : ObjectId("522bf75f6094a4e72db22829"), "name" : "xyz", "tags" : [ "routine", "myTag", "tricep", "myTag2" ] }
{ "_id" : ObjectId("522bf7876094a4e72db2282a"), "name" : "mno", "tags" : [ "exercise", "myTag", "tricep", "myTag2", "biceps" ] }
> db.performant.ensureIndex({tags:1})
> db.performant.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.performant",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"tags" : 1
},
"ns" : "test.performant",
"name" : "tags_1"
}
]
> db.performant.find({tags:{$in:["bicep","chest","trufala"]}}).explain()
{
"cursor" : "BtreeCursor tags_1 multi",
"isMultiKey" : true,
"n" : 2,
"nscannedObjects" : 3,
"nscanned" : 5,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 5,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"tags" : [
[
"bicep",
"bicep"
],
[
"chest",
"chest"
],
[
"trufala",
"trufala"
]
]
},
"server" : "none-6674b8f4f2:27017"
}
> db.performant.find({$or:[{tags:"bicep"},{tags:"chest"},{tags:"trufala"}]}).explain()
{
"clauses" : [
{
"cursor" : "BtreeCursor tags_1",
"isMultiKey" : true,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 10,
"indexBounds" : {
"tags" : [
[
"bicep",
"bicep"
]
]
}
},
{
"cursor" : "BtreeCursor tags_1",
"isMultiKey" : true,
"n" : 0,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"tags" : [
[
"chest",
"chest"
]
]
}
},
{
"cursor" : "BtreeCursor tags_1",
"isMultiKey" : true,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"tags" : [
[
"trufala",
"trufala"
]
]
}
}
],
"n" : 2,
"nscannedObjects" : 3,
"nscanned" : 3,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 3,
"millis" : 10,
"server" : "none-6674b8f4f2:27017"
}
> db.performant.find({$or:[{tags:"bicep"},{tags:"chest"},{tags:"trufala"}]}).sort({tags:1}).explain()
{
"cursor" : "BtreeCursor tags_1",
"isMultiKey" : true,
"n" : 2,
"nscannedObjects" : 15,
"nscanned" : 15,
"nscannedObjectsAllPlans" : 15,
"nscannedAllPlans" : 15,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"tags" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "none-6674b8f4f2:27017"
}