我想为我的ColdFusion应用创建一个点击计数器。我不希望在每个页面命中时更新数据库命中表。理想情况下,我想聚合应用范围中的命中,或某些类型结构中的缓存,然后间歇性地保存它们。
到目前为止我还有想法:。
创意1
问题:我不知道如何在经过一段时间后间歇性地将结构数据导入数据库。预定活动?
创意2
没有饼干;将pageId / ip地址保存在自己的缓存/应用程序结构中。
问题我不确定如何构建数据结构/数组来存储信息。看起来很复杂的数组循环和结构查找。我仍然有与想法相同的问题。
任何建议,想法,批评?特别是,我需要帮助找出想法2的数据结构。我对性能比对数据完整性更感兴趣,并且对CF9唯一解决方案感到满意。 我应该添加我希望将数据非规范化为每个页面ID的页面命中列。我不需要标准化数据表。
答案 0 :(得分:5)
尝试以您描述的方式捕获此数据会引入缓存过期的扩展问题,以避免在您最终希望持久保存到数据库时条目数增加时的OOM或较长的迭代次数。您要聚合的信息已在Web服务器日志中捕获。解析这些是一项简单的活动,您只需要编写一个能够了解这些翻转方式和时间的算法。
使用log = fileRead('log.txt', 'read')
并通过line fileReadLine(log)
定期迭代<cfschedule/>
。对于每个批次,您可以按照已经描述的方式使用,然后根据IP地址使用database approach for INSERT/UPDATE (usually uses the MERGE keyword, but MySQL is different),如果这就是您所追求的。如果它是一个非常高的流量站点,请考虑更改IP address column to an integer datatype to speed index lookups.
<强>更新强>
使用以下代码设置文件对象引用:
<cflock name="logparser" type="exclusive" timeout="1" throwontimeout="false">
<cfif NOT structKeyExists(application, "logFile")>
<cfset application.logFile =
fileOpen('/path/to/log.txt', 'read')>
</cfif>
<cfloop condition="NOT FileisEOF(application.logFile)">
<!--- replace with an appropriate algorithm --->
<cfoutput>
#fileReadLine(application.logFile)#
<br />
</cfoutput>
</cfloop>
</cflock>
这样做会设置一次引用(即fileOpen()
),它会跟踪它所在的行。然后,当<cfschedule/>
再次点击此代码时,它会使用现有引用(如果存在)并从那里向前迭代。锁定确保只有一个线程执行算法 - 所以你不必担心时间限制,只要它需要就让它继续运行。
答案 1 :(得分:1)
创意1:是的,<cfschedule>
是你的朋友
创意2:保存pageId / ip地址?我想这最好使用Set from Java,但是如果你为它分配一个空值,那么struct也会工作......
pageIDs["1"]["192.0.0.1"] = "";
hitsOfPage1 = structCount(pageIDs[1]));
但是,如果我再次访问该页面,我将不会被计算在内?