Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 什么';判断一个新的观察结果是唯一的还是重复以前的观察结果的最有效方法是什么?_Design Patterns - Fatal编程技术网

Design patterns 什么';判断一个新的观察结果是唯一的还是重复以前的观察结果的最有效方法是什么?

Design patterns 什么';判断一个新的观察结果是唯一的还是重复以前的观察结果的最有效方法是什么?,design-patterns,Design Patterns,我正在建立一个知识库网站,对于知识库中的每个页面,我希望能够显示以下统计信息:由Y个不同的人查看X次 计算视图数量非常简单 为了计算总浏览量,我可以在每次加载页面时简单地增加一个页面浏览计数器(用户已登录,因此没有垃圾邮件问题等) 独特页面视图的天真方法-存储所有查看器ID 为了决定是否将新的访问视为新的独特访客,还是将以前的访客视为再次访问,我需要记录哪些人已经看到了该页面 这意味着在每个页面上保存以前的访问者ID。每次访客到达时,我都会检查他们的ID是否存在于商店中。如果有,我什么也不做,如

我正在建立一个知识库网站,对于知识库中的每个页面,我希望能够显示以下统计信息:由Y个不同的人查看X次

计算视图数量非常简单

为了计算总浏览量,我可以在每次加载页面时简单地增加一个页面浏览计数器(用户已登录,因此没有垃圾邮件问题等)

独特页面视图的天真方法-存储所有查看器ID

为了决定是否将新的访问视为新的独特访客,还是将以前的访客视为再次访问,我需要记录哪些人已经看到了该页面

这意味着在每个页面上保存以前的访问者ID。每次访客到达时,我都会检查他们的ID是否存在于商店中。如果有,我什么也不做,如果没有,我附加它。同时,我记录了唯一ID的总数

存储并查找所有ID以计算单个总数

这在编程上非常简单,但感觉很难看。存储多个ID,然后对每个新ID进行查找,只需计算一个整数,这种想法感觉就像是比我更聪明的头脑找到了解决问题的紧凑解决方案

这是标准问题模式吗?

确定新观察结果是独特的还是预先存在的最有效方法是什么

我感兴趣的是,这是否是涉及哈希或类似内容的紧凑解决方案的标准问题


NB我感兴趣的是,是否有一些聪明的数学或算法可以做到这一点。我可以解决它,我只是怀疑有一种更聪明的方法…

在这种情况下,关系数据库可能不是解决这个问题的最有效或最可扩展的方法。我建议查看键值存储,比如Redis,其中键可以是页面标识符,值可以是一个由哈希表支持的集合,请参见这里的大声思考,但让我们看看这在算法上是否有意义:

对于每个页面,存储三个字段:

  • 一个查看计数器,正如您已经拥有的那样

  • 一个“唯一查看器”计数器

  • 一个“bloomfilter”(基本上是一个大的字段,但谷歌提供了实现细节)

当用户点击页面时,为该用户生成哈希。如果该散列已经在bloom筛选器中,只需碰撞视图计数器即可

如果它不在bloom筛选器中,则碰撞两个计数器并将该哈希添加到筛选器中。但是,bloom筛选器成员资格检查中可能会出现误报(但决不会出现误报),这取决于您的散列,因此请注意如何选择散列算法

三个领域。还不错。:)

参考:

编辑:我有一段时间一直在使用这段代码-不确定核心最初来自何处,但多年来我对其进行了调整-为LINQPad做好了准备:

void Main()
{
    var estimatedCount = 100000;
    var falsePositiveProbability = 0.001;
    var falsePositiveCount = 0;
    var memberCount = 0;
    var bloom = BloomFilter<char>.Create(
        estimatedCount, 
        falsePositiveProbability,
        c => c.GetHashCode(),
        c => (int)c);
    var allChars = Enumerable.Range(0, 0xffff).Select(i => (char)i).ToList();
    foreach(var c in allChars)
    {
        var alreadyIn = bloom.Test(c);
        if(alreadyIn)
        {
            falsePositiveCount++;
        }
        bloom.Add(c);
        memberCount++;
    }
    Console.WriteLine("Predicted count: {0} Predicted false positive: {1:p} ", estimatedCount, falsePositiveProbability);
    Console.WriteLine("Actual false positive count: {0} Actual member count: {1} ", falsePositiveCount, memberCount);
    Console.WriteLine("False positive rate: {0:p}", ((double)falsePositiveCount / memberCount));
}

// Define other methods and classes here
public class BloomFilter<TValue>
{
    private BitArray hashbits;
    private int numKeys;

    private Func<TValue,int> _hashFunc1;
    private Func<TValue,int> _hashFunc2;

    public static BloomFilter<TValue> Create(int estimateCount, double falsePositiveRate, Func<TValue,int> hash1, Func<TValue,int> hash2)
    {
        // formulae courtesy of http://hur.st/bloomfilter
        var tableSize = Math.Ceiling((estimateCount * Math.Log(falsePositiveRate)) / Math.Log(1.0 / (Math.Pow(2.0, Math.Log(2.0)))));
        var keyCount = Math.Round(Math.Log(2.0) * tableSize / estimateCount);
        return new BloomFilter<TValue>((int)tableSize, (int)keyCount)
        {
            _hashFunc1 = hash1,
            _hashFunc2 = hash2
        };
    }

    private BloomFilter(int tableSize, int nKeys)
    {
        numKeys = nKeys;
        hashbits = new BitArray(tableSize);
    }

    public bool Test(TValue val)
    {
        var hashKeys = GenerateHashes(val);
        foreach (int hash in hashKeys)
        {
            if (!hashbits[hash])
                return false;
        }
        return true;
    }

    public bool Add(TValue val)
    {
        bool rslt = true;
        var hashKeys = GenerateHashes(val);
        foreach (int hash in hashKeys)
        {
            if (!hashbits[hash])
            {
                rslt = false;
                hashbits[hash] = true;
            }
        }
        return rslt;
    }

    private int[] GenerateHashes(TValue val)
    {
        int hash1 = _hashFunc1(val);
        int hash2 = _hashFunc2(val);

        var hashKeys = new int[numKeys];

        hashKeys[0] = Math.Abs(hash1 % hashbits.Count);
        if (numKeys > 1)
        {
            for (int i = 1; i < numKeys; i++)
            {
                hashKeys[i] = Math.Abs((hash1 + (i * hash2)) %
                    hashbits.Count);
            }
        }
        return hashKeys;
    }
}
void Main()
{
var估计数=100000;
var假阳性概率=0.001;
var falsePositiveCount=0;
var memberCount=0;
var bloom=BloomFilter.Create(
估计数,
假阳性概率,
c=>c.GetHashCode(),
c=>(int)c);
var allChars=Enumerable.Range(0,0xffff).Select(i=>(char)i.ToList();
foreach(所有字符中的变量c)
{
var alreadyIn=布鲁姆试验(c);
如果(alreadyIn)
{
假阳性计数++;
}
加入(c);
memberCount++;
}
WriteLine(“预测计数:{0}预测假阳性:{1:p}”,估计计数,假阳性概率);
WriteLine(“实际误报计数:{0}实际成员计数:{1}”,误报计数,成员计数);
WriteLine(“假阳性率:{0:p}”,((双)假阳性计数/memberCount));
}
//在此处定义其他方法和类
公共类过滤器
{
专用位数组散列位;
纽基私人酒店;
私有Func_hashFunc1;
私有Func_hashFunc2;
公共静态BloomFilter创建(int estimateCount、双误报率、Func哈希1、Func哈希2)
{
//公式由http://hur.st/bloomfilter
var tableSize=数学上限((估计计数*数学日志(假阳性))/Math.Log(1.0/(数学功率(2.0,数学日志(2.0 ')));
var keyCount=Math.Round(Math.Log(2.0)*表大小/estimateCount);
返回新的BloomFilter((int)表大小,(int)键计数)
{
_hashFunc1=hash1,
_hashFunc2=hash2
};
}
私有BloomFilter(int tableSize,int nKeys)
{
numKeys=nKeys;
hashbits=新的位数组(表大小);
}
公共布尔测试(TValue val)
{
var hashKeys=generatehash(val);
foreach(哈希键中的int散列)
{
if(!hashbits[hash])
返回false;
}
返回true;
}
公共bool Add(TValue val)
{
bool rslt=真;
var hashKeys=generatehash(val);
foreach(哈希键中的int散列)
{
if(!hashbits[hash])
{
rslt=假;
hashbits[hash]=true;
}
}
返回rslt;
}
私有int[]生成灰烬(TValue val)
{
int hash1=_hashFunc1(val);
int hash2=_hashFunc2(val);
var hashKeys=newint[numKeys];
hashKeys[0]=Math.Abs(hash1%hashbits.Count);
如果(numKeys>1)
{
对于(int i=1;i
+1个有趣的问题。我不知道他们是否