使用LeanCloud平台为Hexo博客添加文章浏览量统计组件

在原来的wordpress博客中有一个WP-PostViews Plus插件,可以统计每篇文章的浏览量,可以为游客提供热门文章的信息,(顺便满足一下作者的虚荣心)。现在切换到静态博客Hexo了,就需要第三方服务来实现这样的动态数据处理。这里要感谢师弟ariwaranosai给我推荐的LeanCloud平台,以及为hexo博客添加访问次数统计功能(基于BAE)提供的思路。使用LeanCloud的优点是它自己实现了一个AV.view 类,不需要考虑JavaScript的跨站访问问题。

创建Lean Cloud应用

首先一句话介绍Lean Cloud:

LeanCloud(aka. AVOS Cloud)提供一站式后端云服务,从数据存储、实时聊天、消息推送到移动统计,涵盖应用开发的多方面后端需求。

我们只用到它的数据存储部分,具体步骤如下:

  1. 首先到『控制台』创建一个应用,名字随便取。
  2. 点击新建应用的『数据』选项,选择『创建Class』,取名为”Counter“。
  3. 点击新建应用右上角的齿轮,在『应用Key』选项里得到APP ID 和 APP Key,在后面会用到。

修改Hexo页面

新建popular_posts.ejs

首先在theme/你的主题/layout/_widget目录下新建popular_posts.ejs文件,其内容为

1
2
3
4
5
6
7
8
9
<% if (site.posts.length){ %>
<div class="widget-wrap">
<h3 class="widget-title">浏览数目</h3>
<div class="widget">
<ul class="popularlist">
</ul>
</div>
</div>
<% } %>

修改head.ejs

修改theme/你的主题/layout/_partial/head.ejs文件,在head标签的最后插入:

1
2
<script src="https://cdn1.lncld.net/static/js/av-min-1.2.1.js"></script>
<script>AV.initialize("你的APP ID", "你的APP Key");</script>

注意Lean Cloud引用的js文件位置可能会变化,如果代码里位置打不开的话,记得去官方的JavaScript SDK文档找一下最新的位置。

修改after-footer.ejs

修改theme/你的主题/layout/_partial/after-footer.ejs文件,在最后插入:

Read More

博客迁移小记

一点闲话

扯一点闲话,这半年发生了不少事,导致博客断更了半年多。一言难尽,就上一句心灵鸡汤来概括吧,顺便弘扬一下正能量:

所有的事情最后都会有好结局,如果你觉得结局不好,那是因为还没有到最后。

迁移原因

进入正题,这两天闲下来之后,也是起了心思,想把博客从wordpress迁移到静态博客上,原因如下:

  1. 最近用惯了markdown,想更方便地写东西,更加专注于内容。而wordpress没有好用的markdown插件,以前都是写tex里然后往博客上粘贴,太麻烦了。
  2. 作为一个不称职的程序员,用了这么久的wordpress,现在终于想要有一点control every thing的感觉,自己动手折腾个静态博客,顺便学习一下javascript,jquery,css基础。
  3. 还有就是静态博客的普遍优点了,比如不用服务器,省了买空间的钱(免费的Github Pages),访问速度快,容易被搜索引擎抓取等。

静态博客先使用了Github推荐的Jekyll,发现需要自己搞的东西太多,于是转用了基于node.js的Hexo。Hexo有以下优点:

  1. 生成文章速度非常快。
  2. 命令简单,只需要会hexo nhexo ghexo shexo d就能 搞定一切。
  3. 中文用户多,文档和插件比较全。
  4. 能通过插件解决markdwon和mathjax冲突问题。

搭建参考

在搭建过程,主要参考了以下文章:

以上的文章已经足够基本了解hexo博客的整个搭建过程了,只需要照做即可。我的博客主题是基于landscape-plus改的,另外参考了howiefh的 landscape-f主题,添加了多说最近评论小部件以及我自己写的浏览计数小部件。图片都托管在七牛云存储上。

迁移问题

在博客从wordpress迁移到hexo的过程中,主要碰到的问题及解决办法如下:

  1. 原wordpress博客链接的死链问题。原先我wordpress文章链接用的是坑爹的默认生成方式,是通过?传p的参数来获取文章的URL。问题是p是个随机数字,我又没办法在静态页面上动态地获取p的值做重定向。现在折衷的解决办法是暂时不改域名,先用着github提供的二级域名,然后在原域名上用wordpress的Redirect插件对文章链接做301重定向,看看搜索引擎能不能把原文章的URL给改了。 (我会尽快把这个域名的DNS解析转到github的博客上来)。目前你可以通过www.crescentmoon.info访问原wordpress博客,但是点击任何文章都会跳转到新博客来:-D。这个没有成功,请从搜索引擎点文章名过来的读者在博客页面寻找一下那篇文章吧囧。
  2. mathjax和markdown渲染冲突问题。因为markdown的解析要优先于mathjax,所以经常会导致mathjax渲染失败,需要玩一些tricks,比如latex语法中的下标’_‘要改成转义的’\_’, equation环境需要套一个div标签或者rawblock环境等,带来了无穷无尽的麻烦。还好hexo上有大神写的hexo-renderer-pandoc插件,用pandoc去代替默认的markdown渲染器,完美地解决了这个问题。
  3. 文章的浏览数小部件问题。原先我的wordpress有个显示文章浏览数的小插件,现在换成静态网页了,就必须用第三方的服务实现这个功能,具体请见下一篇博客啦。
  4. 多说评论没有跟过来的问题,这个正在解决中。

我是否吃遍了食堂的盘子?

前一阵子突发奇想,想看看吃饭吃了这么久,是不是把食堂里的盘子都吃过一遍了。提出问题如下: 现存在1,2,3号个盘子,每次吃饭拿一个盘子,用完之后放回去,请问吃了5次饭之后三个盘子都被用过的概率是多少?如果是m个盘子,吃了n次饭所有的盘子都被用过的概率呢?

求概率

虽然我猜出了公式,但是还是不怎么懂。。。讲一下猜的过程:

  1. 3个盘子吃了5次饭的情况。 既然我要算所有盘子都被吃过的情况,那么只要排除掉盘子没吃过的情况就好了。首先考虑只用了2个盘子的情况,总够有\(C^2_3 \cdot 2^5\)种。但是要注意到这里对2个盘子的穷举已经包括了只用了1个盘子的情形而且还冗余了,所以要减掉冗余的3种情况。 所以三个盘子都被用过的概率为:
    \[1-\frac{C^2_3 \cdot 2^5 -3}{3^5}=\frac{150}{243}\]
  2. 4个盘子吃了5次饭的情况。 这里我们首先考虑只用了3个盘子的情况,共有\(C^3_4 \cdot 3^5\)种情况。但是对这3个盘子的情况的列举已经包括了只包含2个盘子的情况,所以要减去\(C^2_4 \cdot 2^5\)种2个盘子的情况,但是要注意的是对这2个盘子的列举又已经包括了1个盘子的情况,所以要加上种只含一个盘子的情况\(C^1_4 \cdot 1^5\)补回来。 所以三个盘子都被用过的概率为:
    \[ 1-\frac{C^3_4 \cdot 3^5-C^2_4 \cdot 2^5+C^1_4 \cdot 1^5}{4^5}=\frac{240}{1024} \]
  3. m个盘子吃了n次饭的情况。 根据上面的减减加加的想法推断(完全是瞎猜好么),就可以得到m个盘子吃了n次饭的概率公式:
    \[ 1-\frac{C^{m-1}_n \cdot (m-1)^n-C^{m-2}_n \cdot (m-2)^n+... \pm C^1_n \cdot 1^n}{m^n} \]
    m个盘子都被用过的概率为: 随便代入一个例子。m=20,n=50得到的概率为:0.16417976964878256。用模拟的方法发现这个数是对的- -。

求期望

虽然我们知道了具体的概率,还是希望有个期望值来告诉我们大概在吃几个盘子的时候你能够舔遍全食堂的盘子。根据《算法导论》5.4.2的说法,我们将吃到以前没吃过的盘子的时候定义为“命中”,然后我们要求为了吃完m个盘子需要吃的次数n。

命中次数可以用来讲n次吃饭划分为多个阶段。第i个阶段包括从第i-1次命中到第i次命中所吃的次数。第1阶段因为所以盘子都没被吃过,所以是必中的。第i阶段的每一次吃饭,都有i-1个盘子被吃过,m-i+1个盘子没被吃过,这样第i次命中的概率就是(m-i+1)/m。

\(n_i\)表示第i阶段的吃饭次数。每个随机变量\(n_i\)都服从概率为(m-i+1)/m的几何分布。根据几何分布的期望可以算得
\[ E[n_i]=\frac{m}{m-i+1}\]
由期望的线性性质,可以得到
\[E[n]=E[\sum^m_{i=1}n_i]=\sum^m_{i=1}E[n_i]=\sum^m_{i=1}\frac{m}{m-i+1}=m \sum \frac{1}{m}=m(\ln m+O(1))\]

最后的式子是调和级数的上界,所以我们希望吃完所有的盘子大概需要\(m\ln m\)次,这个问题也被称作赠卷收集者问题(coupon collector’s problem)。 如果食堂有1000 个盘子,我们大学4年估计是吃不完的。。。

有趣的三门问题(蒙提霍尔问题)

三门问题(Monty Hall problem),是一个源自博弈论的数学游戏问题,大致出自美国的电视游戏节目Let’s Make a Deal。问题的名字来自该节目的主持人蒙提·霍尔(Monty Hall)。问题非常的有意思^_^,给出叙述如下:

在三扇门中的某扇门以后有一个奖品,选中这扇门就能拿到门后的奖品。你选定了一扇门,具体地说,假设你选择了1号门。这时候主持人蒙提·霍尔会打开剩下两扇门的其中一扇,你看到门后没有奖品。这时候他给你一个机会选择要不要换另外一扇没有打开的门。你是选择换还是不换呢?

答:因为我之前就选了,换或者不换机会都是均等的,所以换不换无关紧要╮(╯▽╰)╭。 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 真的是这样么?仔细分析一下,游戏过程中你做了2个操作: 第一,你选择了一扇门。第二,你选择了换门或者不换。 定义事件\(A\)为你第一次就选中奖品。 定义事件\(B\)为你换门选中奖品。 那么\(A^c\)为集合A的余集,即第一次没有选中奖品。同理,\(B^c\)为换门没有选中奖品。整个游戏过程中,\(A\)\(A^c\)先发生,\(B\)\(B^c\)再发生。 显而易见的是 \[P(A)=1/3,P(A^c)=2/3\] 要注意的是,在第一次操作之后,还有一件事——主持人打开了一扇没有奖品的门。值得注意的是,这里主持人的动作是跟你第一次选择有关系的:

  1. 如果你一开始就选中了奖品,即事件\(A\)发生了,那么他就在剩下的两扇没有奖品的门之间任选一门打开。接下来,如果你选择换门,那么抽中的概率为0,不换抽中的概率为1。 即 \[P(B|A)=0,P(B^c|A)=1\] 因为事件\(B\)\(B^c\)是在事件A发生之后发生的,所以这里的概率是基于事件\(A\)的条件概率。

  2. 如果你开始没有选中奖品,即事件\(A^c\)发生了,那么他只能打开另一扇没有奖品的门。这时候,如果你选择换门,那么抽中的概率为1,不换抽中的概率为0。 即 \[P(B|A^c)=1,P(B^c|A^c)=0\] 这里的概率是基于事件\(A^c\)的条件概率。

由上我们可以发现一点,事件\(A\)会影响事件\(B\)的概率,即事件\(A\)和事件\(B\)并不是相互独立的。\(A^c\)\(B^c\)也是同理。 于是,利用全概率公式,我们可以求得换门选中奖品的概率为 \[P(B)=P(B|A)P(A)+P(B|A^c)P(A^c)=0*1/3+1*2/3=2/3\] \[P(B^c)=P(B^c|A)P(A)+P(B^c|A^c)P(A^c)=1*1/3+0*2/3=1/3\] 所以事实上你换门能得到奖品的概率为2/3,是不换门的2倍(懂点数学真好啊)。是不是和直觉不太一样?个人认为,直观上觉得\(P(B)=1/2\)的原因是忽略了第一次选择时,通过主持人的动作改变了换门的事件概率这一客观过程。 2013年7月3日更新
从信息论的角度来说,B事件的熵为H(B),在A事件发生之后B事件的条件熵为H(B|A),可以证明 \[H(B) \geq H(B|A) \] 也就是说,在给予了A的信息之后,B的不确定性下降了。