﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-Kuberski - 酷伯司机</title><link>http://www.cnblogs.com/kuber/</link><description>写在代码边上</description><language>zh-cn</language><lastBuildDate>Tue, 07 Oct 2008 19:09:12 GMT</lastBuildDate><pubDate>Tue, 07 Oct 2008 19:09:12 GMT</pubDate><ttl>60</ttl><item><title>Chrome, 浏览器还重要吗</title><link>http://www.cnblogs.com/kuber/archive/2008/09/04/1283861.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Thu, 04 Sep 2008 04:05:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/09/04/1283861.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1283861.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/09/04/1283861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1283861.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1283861.html</trackback:ping><description><![CDATA[
Keso在<a href="http://blog.donews.com/keso/archive/2008/09/04/1342313.aspx">理解Chrome</a>中说, Chrome意在云计算, 说的非常对. 不过我觉得google之所以要推出Chrome, 不是因为在云计算中浏览器越来越重要, 而是因为浏览器也许已经不再重要.<br><br>遵
循摩尔定律, pc机(以及其他计算终端, pda, 手机)的计算能力飞速发展, 因此需要充分利用每个用户自己手里的计算能力,
而不能仅仅依靠自己的servers. Gmail的惊艳就是因为它使用了ajax技术, 把大部分UI的工作丢给了客户端,
使得UI的响应速度大大提高. 从减轻服务器负载, 提高并发能力的角度, 也应该把更多的计算丢给客户端.<br><br>云计算不是仅仅把所有计算都
放在服务器, 客户端只要浏览器就行了, pc计算能力也可能是云的一部分.
因此计算机架构从mainframe(一个主机拖n个显示屏)到C/S(计算都在pc, 服务器管数据)再到B/S(计算, UI渲染都在服务器,
浏览器就管解析HTML), 接下来的方向RIA(rich internet application), 更好的利用客户端计算能力,
更好地用户体验, 象web应用一样便于部署, 维护, 同时充分利用云计算的能力.<br><br>微软和Adobe都在这个方向上努力, 企图建立起RIA时代的标准. 微软推出了Silverlight, 吸引desktop和.net开发人员, 同时希望能把客户端用户保留在windows上; <br><br>Adobe
则从flash的巨大市场占有率出发, 推出跨平台的AIR. GMDesk就是一个AIR应用,
它让你可以从桌面程序中使用Google的services:Gmail, Google Calendar, Google Docs and
Google Maps. 比从浏览器中使用google services方便多了. <br><br>在这两个平台上浏览器已经不再重要, 甚至因为flash的跨平台能力, 操作系统也不再重要. 同时它们都能充分利用客户端的计算能力.<br><br>在
这个趋势中Google当然不会缺席. 从Gmail中超强的Ajax到Google Gear, google积累了大量web技术能力,
因此他们从现有的web标准和技术演变(evolve)出自己的RIA框架: 在这个框架中, web标准和js提供跨平台的能力, Google
gear提供离线操作的能力, 解决web应用最大的弊病. 作为容器, web浏览器就成为google最重要的入口. <br><br>从现有
web技术出发有好处, 可以让现在的大量web开发人员马上以google的平台开发, 同时用户也不需要改变什么, 浏览器就是入口,
体验和以前一样, 用户甚至不需要知道RIA的概念.
但是重点是在Google的框架中浏览器和javacript的能力是至关重要的.现有的浏览器能力尤其是javascript的低效远远没有发挥客户端
的计算能力, 和Silverlight和AIR相比, 成为google发展的障碍. <br><br>当google觉得浏览器缓慢的发展使它在与
微软和adobe的竞争中处于劣势, 当开发人员渐渐被Silverlight和AIR吸引走, 它只能自己跳到前台吆喝了, 推出一个自己的浏览器.
从这一点来说google未必在意Chrome的市场占有率, 我觉得Chrome更像一个ShowCase,
让开发人员意识到google的RIA平台的能力, 并吸引他们为此开发. 只要google gear + google
services能占领市场, google不会介意ff和safari安装在更多用户的pc或者mobile上. <br><br>Google在<a href="http://www.google.cn/chrome/intl/zh-CN/why.html?hl=zh-CN">解释为什么推出Chrome</a>时说: "我们需要的不仅仅是一个'浏览'器，而是一个现代化的平台，可以浏览网页，使用网络应用，并支持那些我们刚刚开始着手的功能。...对大多数人来说，浏览器本身并不重要，它只是一个能够运行互联网网页、网站和网络应用等重要程序的工具。"<br><br>对的, 浏览器已经不重要了, 但是google需要它, 因为他们的下一步计划都基于浏览器, google希望能让浏览器依然是用户的入口. 作为一家更习惯从浏览器中抓住用户的公司, google希望能在下一个十年继续这样.&nbsp; 但是google能做到吗?<img src ="http://www.cnblogs.com/kuber/aggbug/1283861.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42828/" target="_blank">[新闻]Mono 2.0 发布 Linux 上的 .NET 框架成熟了吗？</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>google 发布 Google App Engine 文档离线版</title><link>http://www.cnblogs.com/kuber/archive/2008/08/20/GoogleAppEngineOfflineDoc.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Tue, 19 Aug 2008 17:03:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/20/GoogleAppEngineOfflineDoc.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1271834.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/20/GoogleAppEngineOfflineDoc.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1271834.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1271834.html</trackback:ping><description><![CDATA[GAE的SDK提供了一个local的runtime, 让你在本地开发调试app. 但是帮助文档只有在线版本, 所以开发的时候必须要有internet连接(至少我自己离开文档就什么也做不了), SDK 离线开发的能力打了个折扣. <br><br>Google App Engine的<a href="http://googleappengine.blogspot.com/">官方blog</a>今天<a href="http://googleappengine.blogspot.com/2008/08/take-it-with-you-whole-kit-and-caboodle.html">正式发布了一个离线版的文档</a>. 你可以在这里<a href="http://googleappengine.googlecode.com/files/google-appengine-docs-20080816.zip">下载</a>zip包. 文档是HTML格式, 基本上是http://code.google.com/appengine/ 的克隆, 包括了Home, Doc, FAQ, Articles 和 Download页面. 我第一时间download了下来. 在IE里面打开有问题, 一直在刷新. 在FireFox中就正常. 我是IE6. 不知道IE7怎么样. 他们还提到有计划在以后的SDK中附带离线文档.<br><br>GAE team还特地提到了license(<a target="_blank" href="http://creativecommons.org/licenses/by/2.5/">Creative Commons Attribution 2.5 License</a>): "你可以自由地分发此文档以及派生品. 你可以地翻译和分发你的翻译稿. 你可以转换文档格式(如PDF)和分发新格式文档. "<br><br>那么这算是正式的版权声明, 为文档翻译提供了授权.&nbsp; 我已经翻了两篇, 并且会陆续再翻一些我敢兴趣的文档. 谁还有兴趣翻译的, 联系我, 可以交流交流. <br><br><img src ="http://www.cnblogs.com/kuber/aggbug/1271834.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42827/" target="_blank">[新闻]史上九大最强网络黑客</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>(GAE文档翻译)Google App Engine 数据实体关系建模</title><link>http://www.cnblogs.com/kuber/archive/2008/08/19/ModelingEntityRelationshipsInGAE.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Tue, 19 Aug 2008 01:16:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/19/ModelingEntityRelationshipsInGAE.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1270849.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/19/ModelingEntityRelationshipsInGAE.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1270849.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1270849.html</trackback:ping><description><![CDATA[摘要: 原文: http://code.google.com/appengine/articles/modeling.htmlModeling Entity Relationships实体关系建模Rafe Kaplan, Software EngineerJune 2008 Introduction导言Sure, the Getting Started Guide tells you what you n&nbsp;&nbsp;<a href='http://www.cnblogs.com/kuber/archive/2008/08/19/ModelingEntityRelationshipsInGAE.html'>阅读全文</a><img src ="http://www.cnblogs.com/kuber/aggbug/1270849.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42826/" target="_blank">[新闻]微软拟2010年推新版SQL 强化商业智能功能</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>(GAE文档翻译)Google App Engine中如何修改你的数据模型</title><link>http://www.cnblogs.com/kuber/archive/2008/08/15/1268676.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Fri, 15 Aug 2008 06:22:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/15/1268676.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1268676.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/15/1268676.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1268676.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1268676.html</trackback:ping><description><![CDATA[<div id="article_body">原文: http://code.google.com/appengine/articles/update_schema.html<br>

<div>
<div class="jd-descr">我发在译言上的中英文对照版: http://www.yeeyan.com/articles/view/41148/12436/dz<br><div id="article_body">
<h1 class="page_title"><span>更新</span>你<span>的数据模型</span></h1>
<p><span><span class="google-src-text" style="text-align: left;"><em>Mark Ivey, Google Engineer</em></span> </span><br><span><span class="google-src-text" style="text-align: left;"><em></em></span> <em>2008年6月</em></span></p>
<div>
<div class="jd-descr">
<h2><span>导言</span></h2>
<p><span style="font-size: small;"><span style="font-size: 12pt;"></span></span><span style="font-size: small; font-family: Verdana;">GAE</span><span style="font-size: small;"><span style="font-size: 12pt;">应用开发中</span></span><span style="font-size: small; font-family: Verdana;"> </span><span style="font-size: small;"><span style="font-size: 12pt;">不可避免的你会需要修改你的数据模型</span>. <span style="font-size: 12pt;">本文通过一个小例子介绍了修改</span></span><span style="font-size: small;"><span style="font-size: 12pt;">数据模型</span></span><span style="font-size: small;"><span style="font-size: 12pt;">的两个基本步骤:</span><br></span></p>
<ol><li> <span style="font-size: small;"><span>更新数据模型</span>类定义</span></li><li> <span style="font-size: small;"><span style="font-size: 12pt;">更新</span>Datastore<span style="font-size: 12pt;">中的已有数据实体</span>(<span style="font-size: 12pt;">这一步并不是总是必要的</span>, <span style="font-size: 12pt;">下面会</span><span>讲什么时候你需要这样做)。</span></span> </li></ol><h2><span>开始</span>之前</h2>
<p><span>在更新你的数据模型时，</span><span style="font-size: small;"><span>你</span></span><span><span style="font-size: small;">可能需</span><span style="font-size: small;">要暂时</span>禁止用户在你的应用中更新数据。</span> <span>是否确实需要取决于你的应用, 但是在某些情况下, 暂时禁止用户输入会大大便于你更新已有数据。</span></p>
<h2><span>更新你的数据模型</span></h2>
<p><span>这里有一个例子，一个简单的图片：</span></p>
<pre class="prettyprint"><span><span class="google-src-text" style="text-align: left;"><span class="kwd">class</span><span class="typ">Picture</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln"> &nbsp; <br>   author </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">UserProperty</span><span class="pun">()</span><span class="pln"> &nbsp; <br>   png_data </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">BlobProperty</span><span class="pun">()</span><span class="pln"> &nbsp; <br>   name </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">StringProperty</span><span class="pun">(</span><span class="kwd">default</span><span class="pun">=</span><span class="str">''</span><span class="pun">)</span><span class="pln"> &nbsp;</span><span class="com"># 唯一的</span></span><span class="com">的图片名</span></span></pre>
<p><span><span class="google-src-text" style="text-align: left;">我们来修改这个model, 为每个图片加上评分</span>。</span><span>为了保存评分, 我们保存用户评分的次数和评价得分值。</span><span>更新这个数据模型很容易，我们只是增加两个新的属性：</span></p>
<pre class="prettyprint"><span class="kwd">class</span><span class="typ"> Picture</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln"><br>&nbsp; author </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">UserProperty</span><span class="pun">()</span><span class="pln"><br>&nbsp; png_data </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">BlobProperty</span><span class="pun">()</span><span class="pln"><br>&nbsp; name </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">StringProperty</span><span class="pun">(</span><span class="kwd">default</span><span class="pun">=</span><span class="str">''</span><span class="pun">)</span><span class="pln"> &nbsp;</span><span class="com"># </span><span><span class="google-src-text" style="text-align: left;"><span class="com">唯一的</span></span><span class="com">的图片名</span></span><span class="com"></span><span class="pln"><br>&nbsp; </span><strong><span class="pln">num_votes </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">IntegerProperty</span><span class="pun">(</span><span class="kwd">default</span><span class="pun">=</span><span class="lit">0</span><span class="pun">)</span><span class="pln"><br>&nbsp; avg_rating </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">FloatProperty</span><span class="pun">(</span><span class="kwd">default</span><span class="pun">=</span><span class="lit">0</span><span class="pun">)</span></strong></pre>
<p><span>现在所有保存到Datastore的新建实体将获得一个默认的评分为0 。</span><span>请注意，Datastore中现有的数据并没有自动被修改, 所以他们不会有这些属性。</span></p>
<h2><span>更新现有数据实体</span></h2>
<p><span><span class="google-src-text" style="text-align: left;">App Engine datastore</span>并不要求所有数据有相同的一组属性。</span> <span>更新</span>你<span>的数据模型</span><span>之后</span><span>，现有的数据实体将继续没有这些属性。</span> <span>在某些情况下，这就够了，你不需要做什么。</span> <span><span class="google-src-text" style="text-align: left;">那什么时候</span>你想更新现有的数据，使他们也有新的属性？</span> <span>一种情况是当</span>你<span>想要对新的属性做查询。</span>在我们这个Picture的例子中, <span><span class="google-src-text" style="text-align: left;">查询"最受欢迎"或者"最不受欢迎"图片不会返回更新之前的数据, 因为它们没有相应的评分属性</span>。</span><span>要解决此问题，我们需要更新Datastore中现有的数据实体。</span></p>
<p><span>从概念上来说，更新现有的数据实体很容易。</span><span>你只需要创建</span><span><span class="google-src-text" style="text-align: left;">request handler, </span></span><span>取出每个实体，设置新属性的值, 然后保存数据。</span> 有两个我们必须要解决的问题<span>：</span></p>
<ul><li> <span>查询返回数据集有1000条的上限。</span><span>如果有多于1000条记录，需要多次查询以获得所有记录。</span> </li><li> <span><span class="google-src-text" style="text-align: left;">GAE要求http </span></span><span><span class="google-src-text" style="text-align: left;">request </span></span><span><span class="google-src-text" style="text-align: left;">在很短的时间内必须返回</span>，否则</span><span><span class="google-src-text" style="text-align: left;">request </span></span><span>会超时</span><span>。</span><span>如果有很多数据，</span><span><span class="google-src-text" style="text-align: left;">request handler不能在一个请求中处理完所有数据</span></span><span>。</span> </li></ul><div class="jd-descr"><span>解决方法是在一个</span><span><span class="google-src-text" style="text-align: left;">request </span></span><span>中只更新一小部分数据。</span><span>通过使多个</span><span><span class="google-src-text" style="text-align: left;">request</span></span><span>，我们更新所有的数据，而不超过查询上限和request超时限制。为简单起见, </span><span>我们在一个request中只更新一条数据，象这样：</span></div>
<ol><li> <span>读取一个数据实体</span> </li><li> <span>设置属性的值（如果属性有缺省值，会自动设置）</span> </li><li> <span>保存数据</span> </li><li> <span>用meta </span>refresh<span>标记，让浏览器访问更新下一个数据的URL</span> </li></ol><p><span>一句警告：写读取查询时，应避免使用OFFSET(它不适合大数据集)而是使用WHERE语句量限制返回的数据数量。</span><span>如果</span>你<span>的数据已经有某种唯一值的属性，这很容易。</span> <span>在这个例子中，图片<code>名称(name)</code>是唯一的，所以我们对</span><span><code>name</code></span><span>将使用WHERE语句。</span></p>
<p><span>代码如下：</span></p>
<pre class="prettyprint"><strong><span class="com"># Request handler for the URL /update_datastore</span></strong><span class="pln"><br></span><span class="kwd">def</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln"><br>&nbsp; name </span><span class="pun">=</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">request</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">,</span><span class="kwd">None</span><span class="pun">)</span><span class="pln"><br>&nbsp; </span><span class="kwd">if</span><span class="pln"> name </span><span class="kwd">is</span><span class="kwd">None</span><span class="pun">:</span><span class="pln"><br>&nbsp; &nbsp; </span><strong><span class="com"># First request, just get the first name out of the datastore.</span></strong><span class="pln"><br>&nbsp; &nbsp; pic </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">Picture</span><span class="pun">.</span><span class="pln">gql</span><span class="pun">(</span><span class="str">'ORDER BY name DESC'</span><span class="pun">).</span><span class="pln">get</span><span class="pun">()</span><span class="pln"><br>&nbsp; &nbsp; name </span><span class="pun">=</span><span class="pln"> pic</span><span class="pun">.</span><span class="pln">name<br><br>&nbsp; q </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">Picture</span><span class="pun">.</span><span class="pln">gql</span><span class="pun">(</span><span class="str">'WHERE name &lt;= :1 ORDER BY name DESC'</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">)</span><span class="pln"><br>&nbsp; pics </span><span class="pun">=</span><span class="pln"> q</span><span class="pun">.</span><span class="pln">fetch</span><span class="pun">(</span><span class="pln">limit</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln"><br>&nbsp; current_pic </span><span class="pun">=</span><span class="pln"> pics</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"><br>&nbsp; </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">pics</span><span class="pun">)</span><span class="pun">==</span><span class="lit">2</span><span class="pun">:</span><span class="pln"><br>&nbsp; &nbsp; next_name </span><span class="pun">=</span><span class="pln"> pics</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">name<br>&nbsp; &nbsp; next_url </span><span class="pun">=</span><span class="str">'/update_datastore?name=%s'</span><span class="pun">%</span><span class="pln"> urllib</span><span class="pun">.</span><span class="pln">quote</span><span class="pun">(</span><span class="pln">next_name</span><span class="pun">)</span><span class="pln"><br>&nbsp; </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"><br>&nbsp; &nbsp; next_name </span><span class="pun">=</span><span class="str">'FINISHED'</span><span class="pln"><br>&nbsp; &nbsp; next_url </span><span class="pun">=</span><span class="str">'/'</span><span class="pln"> &nbsp;</span><span class="com"># Finished processing, go back to main page.</span><span class="pln"><br>&nbsp; </span><strong><span class="com"># In this example, the default values of 0 for num_votes and avg_rating are</span><span class="pln"><br>&nbsp; </span><span class="com"># acceptable, so we don't need to do anything other than call put().</span></strong><span class="pln"><br>&nbsp; current_pic</span><span class="pun">.</span><span class="pln">put</span><span class="pun">()</span><span class="pln"><br><br>&nbsp; context </span><span class="pun">=</span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="str">'current_name'</span><span class="pun">:</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="str">'next_name'</span><span class="pun">:</span><span class="pln"> next_name</span><span class="pun">,</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="str">'next_url'</span><span class="pun">:</span><span class="pln"> next_url</span><span class="pun">,</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span class="pln"><br>&nbsp; self</span><span class="pun">.</span><span class="pln">response</span><span class="pun">.</span><span class="kwd">out</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="kwd">template</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="str">'update_datastore.html'</span><span class="pun">,</span><span class="pln"> context</span><span class="pun">))</span><span class="pln"><br></span></pre>
<p><span><span class="google-src-text" style="text-align: left;">相应的template显示我们正在更新哪条记录, 并用meta refresh 自动转到下条记录</span>：</span></p>
<pre class="prettyprint"><br><span class="pun">&lt;</span><span class="tag">html</span><span class="pun">&gt;</span><span class="pln"><br></span><span class="pun">&lt;</span><span class="tag">head</span><span class="pun">&gt;</span><span class="pln"><br>&nbsp; </span><strong><span class="pun">&lt;</span><span class="tag">meta</span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"refresh"</span><span class="atn">content</span><span class="pun">=</span><span class="atv">"0;url={{ next_url }}"</span><span class="pun">/&gt;</span></strong><span class="pln"><br></span><span class="pun">&lt;/</span><span class="tag">head</span><span class="pun">&gt;</span><span class="pln"><br></span><span class="pun">&lt;</span><span class="tag">body</span><span class="pun">&gt;</span><span class="pln"><br>&nbsp; </span><span class="pun">&lt;</span><span class="tag">h3</span><span class="pun">&gt;</span><span class="pln">Update Datastore</span><span class="pun">&lt;/</span><span class="tag">h3</span><span class="pun">&gt;</span><span class="pln"><br>&nbsp; </span><span class="pun">&lt;</span><span class="tag">ul</span><span class="pun">&gt;</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="pun">&lt;</span><span class="tag">li</span><span class="pun">&gt;</span><span class="pln">Updated: {{ current_name }}</span><span class="pun">&lt;/</span><span class="tag">li</span><span class="pun">&gt;</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="pun">&lt;</span><span class="tag">li</span><span class="pun">&gt;</span><span class="pln">About to update: {{ next_name }}</span><span class="pun">&lt;/</span><span class="tag">li</span><span class="pun">&gt;</span><span class="pln"><br>&nbsp; </span><span class="pun">&lt;/</span><span class="tag">ul</span><span class="pun">&gt;</span><span class="pln"><br></span><span class="pun">&lt;/</span><span class="tag">body</span><span class="pun">&gt;</span><span class="pln"><br></span><span class="pun">&lt;/</span><span class="tag">html</span><span class="pun">&gt;</span><span class="pln"><br></span></pre>
<p><span>如果你的数据中没有具有唯一值的属性，上面的例子不能直接使用(当某个属性值对应很多条记录时, 它会很慢) 。</span>你<span>需要扩展它以能够处理这种情况。</span><span><span class="google-src-text" style="text-align: left;">但</span>是概念是相同的，使用WHERE限制查询返回的数据集数目以分批更新数据，然后逐条保持。</span></p>
<h2>从<span><span class="google-src-text" style="text-align: left;">Datastore</span>中移除已删除的属性</span></h2>
<p><span>如果你从数据模型中移除了一个属性，你会发现现有的实体仍然有这个属性。</span><span>它仍然会显示在管理控制台(admin console)中，并仍然存在于Datastore众。</span> <span>要真正清理旧数据，你需要的遍历每条记录并逐条移除属性值。</span></p>
<ol><li><span>确认你已从数据模型定义删除了属性。</span> </li><li> <span>如果</span>你<span>的数据模型类继承自db.model ，它改为继承自db.expando 。</span><span>（db.model实例无法</span><span>动态</span><span>修改，这是我们</span><span>在下一步</span><span>要做的） 。</span> </li><li> <span><span class="google-src-text" style="text-align: left;">遍历</span>现有的所有数据（如上文所述） 。</span> <span>对每条数据，使用<code>delattr</code>删除属性，然后保存数据。</span> </li><li><span>如果</span>你<span>的数据模型原本继承自db.model ，不要忘了改回去。</span> </li></ol><h2><span><span class="google-src-text" style="text-align: left;">以后<br></span></span></h2>
<p><span>这种多次request的处理方法现在是可行的。</span> 不过现在我们正在做<span>一些离线处理的</span><span>解决方法。</span><span>当这些成为可用的，可能会提供一个更合理的方式来修改你的数据，而且不用加重服务器的负担。你</span><span>可以考虑订阅<a href="http://googleappengine.blogspot.com/">我们的blog</a>，跟踪最新的进展</span></p>
</div>
</div></div>我的GAE文章: http://www.cnblogs.com/kuber/tag/appengine/<br>我的GAE site: http://feedzshare.appspot.com<br></div>
</div></div><img src ="http://www.cnblogs.com/kuber/aggbug/1268676.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42825/" target="_blank">[新闻]GMail Labs 新功能 - 做数学题确认是否发出邮件</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Google App Engine Helper for Django 更新</title><link>http://www.cnblogs.com/kuber/archive/2008/08/11/1265053.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 11 Aug 2008 03:43:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/11/1265053.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1265053.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/11/1265053.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1265053.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1265053.html</trackback:ping><description><![CDATA[6号(礼拜三, 应该是我们的礼拜四早上了), Google App Engine Helper for Django 发布了更新. 这将是最后一个应用于Diango 0.96的版本. 接下来的Helper将基于Django 1.0.&nbsp; 详细的Release notes见<a href="http://code.google.com/p/google-app-engine-django/source/browse/trunk/CHANGES">这里.</a><br><br>最近一直在看<a href="http://mdp.cti.depaul.edu/">web2py</a>, 好久没有关注Django了, 版本号好像停留在0.96了好长一段时间. 因为这条消息跑去Django的网站看了一下, 原来V1.0已经Alpha2了. V1.0正式版<a href="http://www.djangoproject.com/weblog/2008/aug/08/10-alpha-2/">预计9月份发布</a>. <br><br>之前Django 0.96已经<a href="/yiketudou/archive/2008/03/20/1115043.html">能够在IronPython上跑了</a>. 但是IronPython始终感觉像实验性的东东, 还没有听说有实际的应用. 如果你知道请留言告诉我. <br><br>欢迎交流 Google App Engine开发. <br>欢迎到我开发的第一个GAE app看看: http://www.feedzshare.com<br><br><img src ="http://www.cnblogs.com/kuber/aggbug/1265053.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42824/" target="_blank">[新闻]OpenOffice四处创造纪录 占有全球25%办公软件市场</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Google App Engine 中1M的限制</title><link>http://www.cnblogs.com/kuber/archive/2008/08/08/1263524.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Fri, 08 Aug 2008 03:14:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/08/1263524.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1263524.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/08/1263524.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1263524.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1263524.html</trackback:ping><description><![CDATA[除了'1000'的限制(查询返回记录不能超过1000条)外, 今天发现GAE还有一个'1M'的限制. <br>我在用Memcache缓存一个大List时碰到MemoryError, error message写明了一个cached item不能超过1000000bytes. 跑到<a href="http://groups.google.com/group/google-appengine">group</a>上<a href="http://groups.google.com/group/google-appengine/browse_thread/thread/b9b86f30146a8011#">问了一下</a>. Aral也碰到了同样的问题. 除了memcache外, 原来<a href="http://aralbalkan.com/1434">GAE里面很多地方都有1M的限制</a>(以下翻译自<a href="http://aralbalkan.com/">Aral的blog</a>): <br><ol><li>一个数据结构不能大于1M, 否则会抛出MemoryError</li><li>Response不能返回超过1M的内容, 否则会抛出异常:'TTP response was too large'</li><li>一个Model的实例(相当于一条数据库记录)不能超过1M, 否则会遇到RequestTooLarge 异常. (我曾遇到过这个异常)</li></ol><br>Prateek在回复中还加了一条: Image API 也有1M的限制; Google可能是不希望某个程序员的BT代码把服务器拖垮. 我们从.net的GC运行原理也了解频繁创建生存周期比较短的大对象会影响到程序性能. 在.net中这个标准是85000字节. 大于这个标准的对象在一个专门的堆中分配, 而且一直算是第二代. 因此要么就是这块内存一直不被回收, 要么就是频繁收集第二代对象. <br><br>欢迎和我交流 Google App Engine的开发. 欢迎到我开发的第一个GAE app看看: http://feedzshare.appspot.com<br><img src ="http://www.cnblogs.com/kuber/aggbug/1263524.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42823/" target="_blank">[新闻]云计算硝烟四起 IBM携Bluehouse参战</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>关于FeedzShare</title><link>http://www.cnblogs.com/kuber/archive/2008/08/04/1252687.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 04 Aug 2008 04:23:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/04/1252687.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1252687.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/04/1252687.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1252687.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1252687.html</trackback:ping><description><![CDATA[                  <p><a href="http://www.feedzshare.com">FeedzShare</a> 统计Google Reader和鲜果的读者在<a href="http://www.williamlong.info/archives/824.html" target="_blank">RSS阅读器</a>里面分享的内容, 然后把用户分享最多的文章，也就是最热门的文章呈现在首页上. <a href="http://www.feedzshare.com">FeedzShare</a>可以帮助你过滤和发现中文互联网上的热门信息.<br></p><a href="http://www.feedzshare.com">FeedzShare</a>最初源于我自己的一个工具. 我在Google Reader中订了好多Google Reader Sharing, 有朋友的, 也有一些知名IT博客的(<a href="http://www.google.com/reader/shared/09166964415516033892">Keso</a>, <a href="http://www.google.com/reader/shared/user/12861038172262976459/state/com.google/broadcast">Caozenghui</a>等), 每天都有上百个推荐. 结局就是我的Google Reader未读数一直在1000+. 而且其中不少朋友的分享有重复的,&nbsp; 看完了还要一个一个地点成Read状态. 于是我自己做了一个工具, 聚合所有这些推荐的RSS并统计出被推荐的次数,&nbsp; 被推荐的次数越多的我认为阅读价值就越高. 然后自己烧制成一个feed.&nbsp; 这样我只要订阅我自己烧制的这个feed就可以看到最热门的blog了.&nbsp; <br><br>08年初<a href="http://www.readburner.com">ReadBurner</a>推出后很受欢迎, 让我感觉到这个工具应该会有很多人需要. 而且<a href="http://www.readburner.com">ReadBurner</a>主要是英文内容, 对中文读者不是很方便. 于是我自己写了个爬虫自动在网上找到Google Reader和鲜果的分享Feed, 并建立了一个首页. 现在<a href="http://www.feedzshare.com">FeedzShare</a>的首页上你可以看到读者推荐的热门内容和多少人推荐了它, 点击进入后你还能看见有谁推荐了这篇文章.&nbsp; 除了在网页上阅读你也可以订阅重新烧制的全文RSS.&nbsp; <br><br>刚开始这个工具是用asp.net MVC + SubSonic开发的, Google 推出App Engine后又用Python重写了一遍, 现在host在GAE上(你从URL应该也能看出来).&nbsp; 因为都是业余时间在做, 做的很慢. 从申请GAE, 学习Python到上线差不多用了一个多月时间. <br><br>我觉得基于RSS的聚合和过滤会是将来很重要的一种应用. 现在的FeedzShare还只是个开始. 我非常想听见你的声音: 觉得这个工具好还是不好,&nbsp; 有什么需要改进的, 有任何意见和建议, 或者你想跟我交流GAE的开发, 请留言或者联系我.&nbsp; <br><br>我的GAE开发随笔:<br><div class="PostList">
			<div class="postTitl2"><a id="PostsList1_rpPosts_ctl02_TitleUrl" href="../archive/2008/07/26/1249617.html">Google App Engine的全文搜索api</a><span class="postDesc2"></span><br></div>
							
		</div>
	
		<div class="PostList">
			<div class="postTitl2"><a id="PostsList1_rpPosts_ctl03_TitleUrl" href="../archive/2008/07/25/1251472.html">Google App Engine SDK 更新</a><span class="postDesc2"></span>&nbsp; <br></div>
							
		</div>
	
		
			<div class="postTitl2"><a id="PostsList1_rpPosts_ctl04_TitleUrl" href="../archive/2008/07/01/1232717.html">Google App Engine 中数据库(DataStore)的限制</a><span class="postDesc2"></span><br></div><br><br><br><br><br><img src ="http://www.cnblogs.com/kuber/aggbug/1252687.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42822/" target="_blank">[新闻]唱片商解密缘何反百度：态度强硬 人工干预明显</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Yuil换了个马甲又回来了</title><link>http://www.cnblogs.com/kuber/archive/2008/08/04/1259616.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 04 Aug 2008 01:59:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/08/04/1259616.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1259616.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/08/04/1259616.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1259616.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1259616.html</trackback:ping><description><![CDATA[雅虎<a rel="nofollow" href="http://www.techcrunch.com/2008/07/09/yahoo-radically-opens-web-search-with-boss/" target="nw">BOSS API</a>和<a rel="nofollow" href="http://code.google.com/appengine/" target="nw">Google's App Engine</a>基础上的Mashup应用，一个搜索结果比号称是谷歌杀手Cuil还要好的搜索引擎. 前两天, 作者在blog上说Yuil已经<a href="http://www.javarants.com/2008/07/30/yahoo-boss-is-easy-meet-yuil/" target="nw">死掉了</a>.<br><br>今天Yuil的作者在Blog上更新说, Yuil换了个域名又回来了:<a href="http://www.javarants.com/2008/08/01/yuil-is-dead-4hoursearch-is-now-online/" rel="bookmark">Yuil is dead! 4hoursearch is now online.</a> 而且还提供了源代码下载.<br>为什么叫 4HourSearch.com, 作者说:<br>Why <a onclick="javascript:pageTracker._trackPageview('/outgoing/www.4hoursearch.com');" href="http://www.4hoursearch.com/">4hoursearch</a>?
&nbsp;It took 4 hours to write the initial code, 4 hours for it to go from
unknown to 20 hits / second, 4 hours looking for a domain name and 4
hours to build the brand new UI. &nbsp;Fortunately, it won’t take 4 hours to
find something with it <img src="http://www.javarants.com/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley"><br><br>4小时, 是不是不可思议? 如果你知道作者是Yahoo的平台部门副总裁(Yahoo VP of Platform), 可能就没有那么惊讶了.&nbsp; 让我觉得有趣的是Yuil居然是用Google App Engine.&nbsp; 用Google的运算平台来实现基于Yahoo的Open API的搜索应用, 这才是开放的Internet, 云计算真的很cool. <br>另外一方面, Yahoo是时候该推出他们自己的GAE了. <br><br><br><br><br><img src ="http://www.cnblogs.com/kuber/aggbug/1259616.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42822/" target="_blank">[新闻]唱片商解密缘何反百度：态度强硬 人工干预明显</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Google App Engine的全文搜索api</title><link>http://www.cnblogs.com/kuber/archive/2008/07/26/1249617.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Sat, 26 Jul 2008 07:25:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/26/1249617.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1249617.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/26/1249617.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1249617.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1249617.html</trackback:ping><description><![CDATA[搜索是<a href="http://code.google.com/appengine/">Google App Engine</a>被广泛要求的一个特性. 其实最新的GAE SDK中已经提供了搜索API, 可能因为还没有成熟, 还没有被公开. 但是在GAE的文档中可以找到一些痕迹.<br><br>Google App Engine 的官方文档<a href="http://code.google.com/appengine/articles/bulkload.html">Uploading Data with Bulk Data Uploader</a>中的示例演示了如何加入搜索功能:<br>首先把Entity设为Searchable:<br>&nbsp; def HandleEntity(self, entity):<br>&nbsp;&nbsp;&nbsp; ent = search.SearchableEntity(entity)<br>&nbsp;&nbsp;&nbsp; return ent<br><br>接下来你就可以对此entity做Search了:<br>&nbsp;&nbsp;&nbsp; query = search.SearchableQuery('Person')<br>&nbsp;&nbsp;&nbsp; query.Search(keyword)<br>&nbsp;&nbsp;&nbsp; for result in query.Run():<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.response.out.write('%s' % result['email'])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>可以看到, 代码引用了 google.appengine.ext.search. 下载的SDK有GAE的源码, 我们可以带代码中去看个究竟: C:\Program Files\Google\google_appengine\google\appengine\ext\search\__init__.py (这是我机器上的路径, 你安装的路径可能会不同)<br>\search\__init__.py中有三个类:<br>SearchableEntity<br>SearchableQuery<br>SearchableModel<br><br>SearchableModel是db.Model的子类要使用SearchableModel, 你的model必须从SearchableModel继承, 而不是db.Model; 你可以使用query方法search:<br>&nbsp;&nbsp; query = Article.all().search("sausages cheese dogs")<br><a href="http://appengineguy.com">App Engine Guy</a> 在blog中说明了<a href="http://appengineguy.com/2008/06/how-to-full-text-search-in-google-app.html">怎么使用SearchableModel</a><br><br>目前的搜索API还很简单, 只有精确匹配, 没有短语, 没有语法变化, 也不支持自己增加Stop words, 更没有文档. Google应该在接下来的releases中逐步增强这个功能, 毕竟搜索是google的强项, 不能想象gogole的web hosting平台没有搜索支持. 让我们拭目以待吧.<br><br>我的Google App Engine随笔:<br><a href="/kuber/archive/2008/07/23/1249617.html">Google App Engine的全文搜索api</a><br><a href="/kuber/archive/2008/07/01/1232717.html">Google App Engine 中数据库(DataStore)的限制</a><br>
<h2><a class="singleposttitle" id="AjaxHolder_ctl01_TitleUrl" href="/kuber/archive/2008/07/01/1232717.html"><br></a></h2><br><img src ="http://www.cnblogs.com/kuber/aggbug/1249617.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42821/" target="_blank">[新闻]国外媒体评出史上十大悬疑网络犯罪</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Google App Engine 更新,一个账号现在可以创建10个application了</title><link>http://www.cnblogs.com/kuber/archive/2008/07/25/1251472.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Fri, 25 Jul 2008 08:34:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/25/1251472.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1251472.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/25/1251472.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1251472.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1251472.html</trackback:ping><description><![CDATA[<a href="http://code.google.com/appengine">Google App Engine</a> 的Blog报道了GAE最近的<a href="http://googleappengine.blogspot.com/2008/07/some-small-updates.html">更新</a>:<br>&nbsp;<br><ol><li>一个账号现在可以创建10个application了, 以前是3个</li><li>管理界面中流量报表更精确, 可以Zoom In查看最近6, 12, 24 小时的报表</li><li>可以导出log. 调用appcfg.py</li><li>在程序中使用当前登录用户的email地址发邮件. </li></ol><br>你需要更新你的SDK, 获取最新的API. 我的经验, 每次在本地启动运行Dev Server, 都会自动检查更新的.<br><br>我的Google App Engine技术文章:<br><a href="../archive/2008/07/23/1249617.html">Google App Engine 未公开的Search API</a><br><a href="../archive/2008/07/01/1232717.html">Google App Engine 中数据库(DataStore)的限制</a><br><img src ="http://www.cnblogs.com/kuber/aggbug/1251472.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42820/" target="_blank">[新闻]AMD拆分方案已确认 获阿联酋84亿美元投资</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>转载:通过Google Ajax Libraries API加速你的js脚本的加载 </title><link>http://www.cnblogs.com/kuber/archive/2008/07/23/1249795.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 23 Jul 2008 08:40:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/23/1249795.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1249795.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/23/1249795.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1249795.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1249795.html</trackback:ping><description><![CDATA[<p>原来想介绍这个Google Ajax Library, 在网上搜到了这篇文章, 写的比我好多了, 就转到这里吧, 希望能对大家有用.</p><h2>通过Google Ajax Libraries API加速你的js脚本的加载</h2>

			
				<p>原文链接: http://xuming.net/2008/05/ajax-libraries-api.html</p><p><br></p><p>Google 的触角似乎是无所不在的。在互联网的各个角落，我们都可以看到他的身影。</p>
<p>Google 花费了大量的时间来使网络应用变得更快，调用js脚本是我们经常要用到的功能之一，过多的脚本调用经常会使网页变慢。</p>
<p>Google似乎试图来解决这个问题，使大家在使用Javascript框架的时候能够更快速和简单，为此，Google最新提供了一个名为 <a href="http://code.google.com/apis/ajaxlibs/">Ajax Libraries API</a>的东西。</p>
<p><span id="more-50"></span></p>
<p>Ajax Libraries API的理念很简单：把Javascript运行在Google的服务器上面, 通过Google快速分发服务器, 当有需要的时候进行Gzip压缩, 更重要的是，使用缓存机制来改善多人同时加载的情况.</p>
<p>使用<a href="http://code.google.com/apis/ajaxlibs/">AJAX Libraries API</a> 有以下优势：</p>
<ul><li>开发者不需要考虑如何设置缓存机制，Google会为你准备好一切 </li><li>如果另外一个应用程序使用了同一个Javascript框架，那么客户端不再需要重复去获取脚本，因为其已经被缓存在用户的机器里面了。 </li><li>不需要考虑网络环境和流量限制 </li></ul>
<p> <a href="http://code.google.com/apis/ajaxlibs/">AJAX Libraries API</a> 目前支持以下JS框架：
</p><ul><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#jquery">jQuery</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#prototype">prototype</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#script_aculo_us">script.aculo.us</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#mootools">MooTools</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#dojo">dojo</a> </li></ul>
<p>如果这个缓存机制能够大规模的得到应用，那么将是无比强大的。只不过，在中国目前的这种状况下，对于其调用速度始终是担心的。</p>
<h3>Ajax Libraries API调用方式1：</h3>
<p>例如：加载Prototype 1.6.0.2 </p>
<p><code>&lt;script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js"&gt;&lt;/script&gt;</code>     </p>
<h3>Ajax Libraries API调用方式2：</h3>
<p>使用<a href="http://code.google.com/apis/ajax/documentation/">Google AJAX API Loader’s google.load() 方法</a>.</p>
<p><code>&lt;script src="http://www.google.com/jsapi"&gt;&lt;/script&gt;      <br>&lt;script&gt;       <br>// Load jQuery       <br>google.load("jquery", "1");       <br>// on page load complete, fire off a jQuery json-p query       <br>// against Google web search       <br>google.setOnLoadCallback(function() {       <br>$.getJSON("http://ajax.googleapis.com/ajax/services/search/web?q=google&amp;;v=1.0&amp;;callback=?",       <br>// on search completion, process the results       <br>function (data) {       <br>if (data.responseDate.results &amp;&amp;       <br>data.responseDate.results.length&gt;0) {       <br>renderResults(data.responseDate.results);       <br>}       <br>});       <br>});       <br>&lt;/script&gt;</code></p>
<p>详细调用方法请 <a href="http://code.google.com/apis/ajaxlibs/documentation/#AjaxLibraries" target="_blank">查看相关文档</a></p><img src ="http://www.cnblogs.com/kuber/aggbug/1249795.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42817/" target="_blank">[新闻]雅虎新闻首页改版，宽屏、共享、组件</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>乔布斯的策略</title><link>http://www.cnblogs.com/kuber/archive/2008/07/23/1249771.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 23 Jul 2008 08:11:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/23/1249771.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1249771.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/23/1249771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1249771.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1249771.html</trackback:ping><description><![CDATA[这篇文章讲了一个<a href="http://hbswk.hbs.edu/archive/3533.html">乔布斯的故事</a>. 乔布斯被风投邀请到另外一家公司看看他们新推出的产品. 乔布斯一如既往的酷. 详细请看<a href="http://apple4.us/2008/07/-scooter.html">apple4.us的翻译</a>. <br><br>我的摘要:<br><b>产品开发</b>: 集中全部精力用于做好一款产品, 没有退路. 孤注一掷才能激发小宇宙.<br><b>产品设计</b>: 三个设计标准：创新,优雅，人性化, 找到"things that would make you shit in your pants." (btw, Jobs好像很喜欢shit这个词啊)<br><b>竞争对手</b>: 技术不是壁垒.关键是用时间和资金去找到其他壁垒.&nbsp; They'll figure out a way around that. 科特勒好像也说过, 技术永远不是核心竞争力. <br><b>市场营销</b>: 高举高打,他自己的话说就是big-bang guy. 看看apple的产品发布就知道了. The risk&nbsp; is that it exposes you to
your enemies. You're going to need a lot of money to fight thieves.<img src ="http://www.cnblogs.com/kuber/aggbug/1249771.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42817/" target="_blank">[新闻]雅虎新闻首页改版，宽屏、共享、组件</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Does Chinese deserve it?</title><link>http://www.cnblogs.com/kuber/archive/2008/07/02/1233911.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 02 Jul 2008 04:55:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/02/1233911.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1233911.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/02/1233911.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1233911.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1233911.html</trackback:ping><description><![CDATA[在<a href="http://freenetproject.org/">FreeNet</a>的首页上看到这样一句话:<i><br>
"I worry about my child and the Internet all the time, even though
she's too young to have logged on yet. Here's what I worry about. I
worry that 10 or 15 years from now, she will come to me and say 'Daddy,
where were you when they took freedom of the press away from the
Internet?'"<br>
<br>
</i>扪心自问, 我很惭愧. <i>I deserve it. We deserve it.<br>
</i><img src ="http://www.cnblogs.com/kuber/aggbug/1233911.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42816/" target="_blank">[新闻]传阿里投资淘宝超40亿元 应对百度C2C</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Google App Engine 中数据库(DataStore)的限制</title><link>http://www.cnblogs.com/kuber/archive/2008/07/01/1232717.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Tue, 01 Jul 2008 01:19:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/01/1232717.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1232717.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/01/1232717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1232717.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1232717.html</trackback:ping><description><![CDATA[做了一个GAE的应用,&nbsp; 在使用Datastore时碰到很多问题. Datastore有很多限制, 和以前使用的关系型数据库不同.&nbsp; 自己总结了一下, 以免以后自己忘记了. :-)<br>本文不是介绍怎么使用Google App Engine Datastore API. <br><br>任何查询都只能返回Entity, 所以必须Select * From SomeEntity. 不能只返回某些字段<br><br>GQL.fetch()可以带limit和offset参数, 返回从指定位置开始的指定条数记录. 但是, 其实datastore返回了offset+limit条记录, 只是在fetch方法中跳过offset条记录, 只返回最后limit条记录; 这一点不像通常的RMDB. 分页时我们经常会用到类似功能, 因此使用fetch(limit, offset)的话效率会是问题. <br><br>GQL.fetch()最多只返回1000条记录, 不管你把limit值设多大. 应该是出于性能的考虑<br><br>痛苦的Count, 在Groups里面被说的最多的Count: 不象在RMDB里面, count()方法其实是把所有符合条件的记录都读出来再算, 因此性能是个大问题. 出于性能考虑Google文档不建议你多使用count, 不建议在可能数据量很大的查询上用count(). <br><br>count()最多也只能返回1000. 原因同fetch(). <br><br>关于count(), Group里面讨论了很多解决方法. 一般是建议你自己实现count(): 在数据库中创建几个计数器, 创建新entity时随机拿出一个计数器加一. 把几个计数器的值相加, 就是最终的count值;<br><br>事务中所有的entity必须在一个entity group中, 事务中不能有select 查询<br><br>非等式过滤条件只能在一个属性(或字段)上. 以下查询就不可以<br><font size="1" color="#a52a2a">SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND height &gt;= :min_height</font><br>你只能对birth_year属性用不等式<br><font size="1" color="#a52a2a">SELECT * FROM Person WHERE birth_year &gt;= :min<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND birth_year &lt;= :max</font><br>&nbsp;&nbsp;&nbsp; &nbsp;<br>如果查询中有不等式,并且有Order By, 不等式查询的字段必须第一个被order by; 以下这两个查询都是错误的:<br><font color="#a52a2a"><font size="1">SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY last_name, birth_year"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY last_name&nbsp;&nbsp;&nbsp;</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>这个才行: <font size="1" color="#a52a2a">SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY birth_year, last_name</font><br><br>看到这么多限制, 是不是觉得很奇怪. Google就拿这么个东西出来现眼吗? Google的解释是这是为了datastore的伸缩性(Scalability). 我的猜测是每个创建的entity会被随机的保存在成百上千的servers中的某个server node上, 使得数据库中aggregation计算代价非常高, 所以更多的计算会被推到app层. 同样的, 事务中所有的entity必须在一个entity group中也是要保证事务中的entity在一个node(或cluster)上. 这仅仅是我的猜想. 有谁知道得更多请留言;<img src ="http://www.cnblogs.com/kuber/aggbug/1232717.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42815/" target="_blank">[新闻]传雅虎最快本月将宣布收购美国在线</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Google新推出Google Media Server</title><link>http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 30 Jun 2008 07:56:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1232516.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1232516.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1232516.html</trackback:ping><description><![CDATA[摘要: Google Desktop上个礼拜发布了一个新Gadget, Google Media Server. 这个软件能自动识别连接到PC上的UPnP媒体设备(PC, XBox, PSP), 播放这些设备上的影音文件. 而且如果你的电视机也支持 UPnP并连接到PC了, 你就可以电视机上观看这些东东. &nbsp;&nbsp;<a href='http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html'>阅读全文</a><img src ="http://www.cnblogs.com/kuber/aggbug/1232516.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42814/" target="_blank">[新闻]周一美国股市科技股惨跌 纳综指创4年新低</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Slope One 之二: C#实现</title><link>http://www.cnblogs.com/kuber/archive/2008/06/18/1224725.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 18 Jun 2008 09:54:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/18/1224725.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1224725.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/18/1224725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1224725.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1224725.html</trackback:ping><description><![CDATA[<a href="/kuber/archive/2008/06/10/1216846.html">上一篇</a>简单介绍了Slope One算法的概念, 这次介绍C#实现<br>使用基于Slope One算法的推荐需要以下数据: <br>
1. 有一组用户<br>
2. 有一组Items(文章, 商品等)<br>
3. 用户会对其中某些项目打分(Rating)表达他们的喜好<br>
Slope One算法要解决的问题是, 对某个用户, 已知道他对其中一些Item的Rating了, 向他推荐一些他还没有Rating的Items, 以增加销售机会. :-)<br>
<br>
一个推荐系统的实现包括以下三步:<br>
1. 计算出任意两个Item之间Rating的差值<br>
2. 输入某个用户的Rating记录, 推算出对其它Items的可能Rating值<br>
3. 根据Rating的值排序, 给出Top Items;<br>
<br>第一步:例如我们有三个用户和4个Items, 用户打分的情况如下表.<br>

 <table x:str="" style="border-collapse: collapse; width: 262pt;" width="349" border="1" cellpadding="0" cellspacing="0"><col style="width: 54pt;" width="72">
 <col style="width: 100pt;" width="133">
 <col style="width: 54pt;" span="2" width="72">
 <tbody><tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="height: 14.25pt; width: 54pt;" width="72" height="19">Ratings</td>
  <td class="xl24" style="border-left: medium none; width: 100pt;" width="133">User1</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">User2</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">User3</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
 </tr>
</tbody></table><br>
在第一步中我们的工作就是计算出Item之间两两的打分之差, 也就是使说计算出以下矩阵:<br>
 <table x:str="" style="border-collapse: collapse; width: 316pt;" width="421" border="1" cellpadding="0" cellspacing="0"><col style="width: 54pt;" width="72">
 <col style="width: 100pt;" width="133">
 <col style="width: 54pt;" span="3" width="72">
 <tbody><tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="height: 14.25pt; width: 54pt;" width="72" height="19">　</td>
  <td class="xl24" style="border-left: medium none; width: 100pt;" width="133">Item1</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">Item2</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">Item3</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">Item4</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">0/3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">0/3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-1/2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/1</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">1/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
 </tr>
</tbody></table><br>
<br>
考虑到加权算法, 还要记录有多少人对这两项打了分(Freq), 我们先定义一个结构来保存Rating:<br>
&nbsp;&nbsp;&nbsp; public class Rating<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float Value { get; set; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int Freq { get; set; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float AverageValue<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get {return Value / Freq;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
我决定用一个Dictionary来保存这个结果矩阵:<br>
&nbsp;&nbsp;&nbsp; public class RatingDifferenceCollection : Dictionary&lt;string, Rating&gt;<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string GetKey(int Item1Id, int Item2Id)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Item1Id + "/" + Item2Id;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public bool Contains(int Item1Id, int Item2Id)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.Keys.Contains&lt;string&gt;(GetKey(Item1Id, Item2Id));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Rating this[int Item1Id, int Item2Id]<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this[this.GetKey(Item1Id, Item2Id)];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set { this[this.GetKey(Item1Id, Item2Id)] = value; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>接下来我们来实现SlopeOne类. 首先创建一个RatingDifferenceCollection来保存矩阵, 还要创建HashSet来保持系统中总共有哪些Items:<br>&nbsp;&nbsp;&nbsp; public class SlopeOne<br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();&nbsp; // The dictionary to keep the diff matrix<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public HashSet&lt;int&gt; _Items = new HashSet&lt;int&gt;();&nbsp; // Tracking how many items totally<br><br>方法AddUserRatings接收一个用户的打分记录(Item-Rating): public void AddUserRatings(IDictionary&lt;int, float&gt; userRatings)<br>AddUserRatings中有两重循环, 外层循环遍历输入中的所有Item, 内层循环再遍历一次, 计算出一对Item之间Rating的差存入_DiffMarix, 记得Freq加1, 以记录我们又碰到这一对Items一次:<br>&nbsp;&nbsp;&nbsp; Rating ratingDiff = _DiffMarix[item1Id, item2Id];<br>&nbsp;&nbsp;&nbsp; ratingDiff.Value += item1Rating - item2Rating;<br>&nbsp;&nbsp;&nbsp; ratingDiff.Freq += 1;<br><br>对每个用户调用AddUserRatings后, 建立起矩阵. 但我们的矩阵是以表的形式保存:<br>
 <table x:str="" style="border-collapse: collapse; width: 208pt;" width="277" border="1" cellpadding="0" cellspacing="0"><col style="width: 54pt;" width="72">
 <col style="width: 100pt;" width="133">
 <col style="width: 54pt;" width="72">
 <tbody><tr style="height: 14.25pt;" height="19">
  <td class="xl26" style="height: 14.25pt; width: 54pt;" width="72" height="19">　</td>
  <td class="xl27" style="border-left: medium none; width: 100pt;" width="133">Rating Dif</td>
  <td class="xl27" style="border-left: medium none; width: 54pt;" width="72">Freq</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">0</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">3</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1-3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">0</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">3</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2-3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1-4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2-4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-0.5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3-4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">0.5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4-3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
 </tr>
</tbody></table><br><br>第二步:输入某个用户的Rating记录, 推算出对其它Items的可能Rating值:<br>public IDictionary&lt;int, float&gt; Predict(IDictionary&lt;int, float&gt; userRatings)<br>也是两重循环, 外层循环遍历_Items中所有的Items; 内层遍历userRatings, 用此用户的ratings结合第一步得到的矩阵, 推算此用户对系统中每个项目的Rating:<br>&nbsp;&nbsp;&nbsp; Rating itemRating = new Rating(); // Prediction of this user's rating <br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; Rating diff = _DiffMarix[itemId, inputItemId]:<br>&nbsp;&nbsp;&nbsp; itemRating.Value += diff.Freq * (diff.AverageValue + userRating.Value);<br>&nbsp;&nbsp;&nbsp; itemRating.Freq += diff.Freq;<br><br>第三步:得到用户的Rating预测后,就可以按rating排序, 向用户推荐了. 测试一下:<br>&nbsp;&nbsp;&nbsp; Dictionary&lt;int, float&gt; userRating userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp; userRating.Add(1, 5);<br>&nbsp;&nbsp;&nbsp; userRating.Add(3, 4);<br>&nbsp;&nbsp;&nbsp; IDictionary&lt;int, float&gt; Predictions = test.Predict(userRating);<br>&nbsp;&nbsp;&nbsp; foreach (var rating in Predictions)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Item " + rating.Key + " Rating: " + rating.Value);<br>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br>输出:<br>Item 2 Rating: 5<br>Item 4 Rating: 6<br><br>改进:<br>观察之前产生的矩阵可以发现, 其中有很多浪费的空间; 例如: 对角线上永远是不会有值的. 因为我们是用线性表保存矩阵值, 已经避免了这个问题;<br>对角线下方的值和对角线上方的值非常对称,下方的值等于上方的值乘以-1; 在数据量很大的时候是很大的浪费. 我们可以通过修改RatingDifferenceCollection来完善. 可以修改GetKey方法, 用Item Pair来作为Key:<br>&nbsp;&nbsp;&nbsp; private string GetKey(int Item1Id, int Item2Id) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Item1Id &lt; Item2Id) ? Item1Id + "/" + Item2Id : Item2Id + "/" + Item1Id ;;<br>&nbsp;&nbsp;&nbsp; }<br>完整代码在<a href="/kuber/articles/SlopeOne_CSharp.html">这里</a>,在.net 3.5上调试通过;<br><strong>参考资料</strong><br> <a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/">tutorial about how to implement Slope One in Python</a><br>
<img src ="http://www.cnblogs.com/kuber/aggbug/1224725.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42813/" target="_blank">[新闻]关于Firefox 3你不知道的八个功能</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>C# Implement of Slope One </title><link>http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 18 Jun 2008 08:57:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1224800.html</wfw:comment><comments>http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1224800.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1224800.html</trackback:ping><description><![CDATA[Here's the source code of my C# implementation of Weighted Slope One. Tested on .net 3.5; The instruction in Chinese can be find <a href="/kuber/archive/2008/06/10/1216846.html">here</a> and <a href="/kuber/archive/2008/06/18/1224725.html">here</a>.<br>Reference:<br><a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/">Tutorial about how to implement Slope One in Python</a><br><a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html">Slope One Predictors for Online Rating-Based Collaborative Filtering</a><br><a href="http://www.guwendong.cn/post/2007/slope_one_algorithm.html">Recommender
Systems: Slope One</a><br><br><br>using System;<br>using System.Collections.Generic;<br>using System.Linq;<br>using System.Text;<br><br>namespace SlopeOne<br>{<br>&nbsp;&nbsp;&nbsp; public class Rating<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float Value { get; set; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int Freq { get; set; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float AverageValue<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return Value / Freq; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; public class RatingDifferenceCollection : Dictionary&lt;string, Rating&gt;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string GetKey(int Item1Id, int Item2Id)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Item1Id &lt; Item2Id) ? Item1Id + "/" + Item2Id : Item2Id + "/" + Item1Id ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public bool Contains(int Item1Id, int Item2Id)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.Keys.Contains&lt;string&gt;(GetKey(Item1Id, Item2Id));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Rating this[int Item1Id, int Item2Id]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this[this.GetKey(Item1Id, Item2Id)];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set { this[this.GetKey(Item1Id, Item2Id)] = value; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; public class SlopeOne<br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();&nbsp; // The dictionary to keep the diff matrix<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public HashSet&lt;int&gt; _Items = new HashSet&lt;int&gt;();&nbsp; // Tracking how many items totally<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddUserRatings(IDictionary&lt;int, float&gt; userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var item1 in userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int item1Id = item1.Key;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float item1Rating = item1.Value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Items.Add(item1.Key);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var item2 in userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (item2.Key &lt;= item1Id) continue; // Eliminate redundancy<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int item2Id = item2.Key;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float item2Rating = item2.Value;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rating ratingDiff;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_DiffMarix.Contains(item1Id, item2Id))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff = _DiffMarix[item1Id, item2Id];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff = new Rating();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _DiffMarix[item1Id, item2Id] = ratingDiff;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff.Value += item1Rating - item2Rating;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff.Freq += 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Input ratings of all users<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddUerRatings(IList&lt;IDictionary&lt;int, float&gt;&gt; Ratings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach(var userRatings in Ratings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AddUserRatings(userRatings);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public IDictionary&lt;int, float&gt; Predict(IDictionary&lt;int, float&gt; userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dictionary&lt;int, float&gt; Predictions = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var itemId in this._Items)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (userRatings.Keys.Contains(itemId))&nbsp;&nbsp;&nbsp; continue; // User has rated this item, just skip it<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rating itemRating = new Rating();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var userRating in userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (userRating.Key == itemId) continue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int inputItemId = userRating.Key;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_DiffMarix.Contains(itemId, inputItemId))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rating diff = _DiffMarix[itemId, inputItemId];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itemRating.Value += diff.Freq * (userRating.Value + diff.AverageValue * ((itemId &lt; inputItemId) ? 1 : -1));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itemRating.Freq += diff.Freq;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Predictions.Add(itemId, itemRating.AverageValue);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Predictions;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Test()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SlopeOne test = new SlopeOne();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dictionary&lt;int, float&gt; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(2, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(3, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test.AddUserRatings(userRating);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(2, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(3, 3);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(4, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test.AddUserRatings(userRating);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(2, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(4, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test.AddUserRatings(userRating);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(3, 4);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDictionary&lt;int, float&gt; Predictions = test.Predict(userRating);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var rating in Predictions)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Item " + rating.Key + " Rating: " + rating.Value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br><br><img src ="http://www.cnblogs.com/kuber/aggbug/1224800.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42813/" target="_blank">[新闻]关于Firefox 3你不知道的八个功能</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>TinyURL的API</title><link>http://www.cnblogs.com/kuber/archive/2008/06/16/1222970.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 16 Jun 2008 04:37:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/16/1222970.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1222970.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/16/1222970.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1222970.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1222970.html</trackback:ping><description><![CDATA[<a href="http://tinyurl.com/">
TinyURL</a>是一个很有用的Web服务, 把你冗长的URL缩短成简单的地址, 比如说这个地址: http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html, 可以变成http://tinyurl.com/3umgrz. 这个例子可能太短了, 如果你有这样一个地址, 并且想发给朋友呢: http://www.amazon.cn/mn/detailApp?qid=1213590566&amp;ref=SR&amp;sr=1-1&amp;uid=168-6604802-9891462&amp;prodid=bkbk831097? 相信博客园的朋友很多都用过这个东东. <br>
<br>
要创建你的tiny url,可以在它的主页去, 输入你的源url. 但是有时候希望在程序中能自动创建, 就需要调用它的接口了. 象Live Writer<a href="http://livesino.net/archives/972.live">这个插件</a>http://livesino.net/archives/972.live, 当发布了一篇日志之后，这个插件使用了 <a href="http://tinyurl.com/">
TinyURL</a> 的服务来缩短日志地址并发到 Twitter让关注你 Twitter 的好友了解最新的日志。<br>
<br>
网上有一些第三方的api, 但其实TinyURL自己开放了一个API, 不知道为什么在它的主页上没有链接. 有知道的同学吱个声.<br>
<br>
API很简单, 调用:http://tinyurl.com/api-create.php?url=http://myURL,&nbsp; 你可以发送一个request到这个地址, Response中只有一个字符串,就是你的tiny url; 很简单吧.<br>
<img src ="http://www.cnblogs.com/kuber/aggbug/1222970.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42812/" target="_blank">[新闻]阿里巴巴联手如家扩张电子商务</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Slope One :简单高效的协同过滤算法(Collaborative Filtering) </title><link>http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Tue, 10 Jun 2008 09:37:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1216846.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1216846.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1216846.html</trackback:ping><description><![CDATA[现在做的一个项目中需要用到推荐算法, 在网上查了一下. <a href="http://www.guwendong.cn/catalog.asp?cate=1">Beyond Search介绍了一个协同过滤算法(Collaborative Filtering)</a> : Slope One;和其它类似算法相比, 它的最大优点在于算法很简单, 易于实现, 执行效率高, 同时推荐的准确性相对很高; <br>
<br>
<strong>基本概念</strong><br>
Slope One的基本概念很简单, 例子1, 用户X, Y和A都对Item1打了分. 同时用户X,Y还对Item2打了分, 用户A对Item2可能会打多少分呢?<br>
<table x:str="" style="border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0" height="130" width="452">
    <col style="width: 54pt;" width="72">
    <col style="width: 131pt;" width="174">
    <col style="width: 121pt;" width="161">
    <tbody>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl24" style="height: 14.25pt; width: 54pt;" height="19" width="72">User</td>
            <td class="xl24" style="width: 131pt;" width="174">Rating to Item
            1</td>
            <td class="xl24" style="width: 121pt;" width="161">Rating to Item
            2</td>
        </tr>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl22" style="height: 14.25pt;" height="19">X</td>
            <td class="xl23" x:num="">5</td>
            <td class="xl23" x:num="">3</td>
        </tr>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl22" style="height: 14.25pt;" height="19">Y</td>
            <td class="xl23" x:num="">4</td>
            <td class="xl23" x:num="">3</td>
        </tr>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl22" style="height: 14.25pt;" height="19">A</td>
            <td class="xl23" x:num="">4</td>
            <td class="xl23">?</td>
        </tr>
    </tbody>
</table>
<br>
根据SlopeOne算法, 应该是:4 - ((5-3) + (4-2))/2 = 2.5. <br>
解释一下. 用户X对Item1的rating是5, 对Item2的rating是3, 那么他可能认为Item2应该比Item1少两分. 同时用户Y认为Item2应该比Item1少1分. 据此我们知道所有对Item1和Item2都打了分的用户认为Item2会比Item1平均少1.5分. 所以我们有理由推荐用户A可能会对Item2打(4-1.5)=2.5分;<br>
<br>
很简单是不是? 找到对Item1和Item2都打过分的用户, 算出rating差的平均值, 这样我们就能推测出对Item1打过分的用户A对Item2的可能Rating, 并据此向A用户推荐新项目.<br>
这里我们能看出Slope One算法的一个很大的优点, 在只有很少的数据时候也能得到一个相对准确的推荐, 这一点可以解决Cold Start的问题.<br>
<br>
<strong>加权算法</strong><br>
接下来我们看看加权算法(Weighted Slope One). 如果有100个用户对Item1和Item2都打过分, 有1000个用户对Item3和Item2也打过分. 显然这两个rating差的权重是不一样的. 因此我们的计算方法是<br>
(100*(Rating 1 to 2) + 1000(Rating 3 to 2)) / (100 + 1000)<br>
<br>
上面讨论的是用户只对项目的喜好程度打分.还有一种情况下用户也可以对项目的厌恶程度打分. 这时可以使用双极SlopeOne算法(BI-Polar SlopeOne). 我还在研究这篇论文,搞懂了再写吧, 呵呵;<br>
<br>
<strong>参考资料</strong><br>
Slope One 算法是由 Daniel Lemire 教授在 2005 年提出. <a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html">这里可以找到论文原文(PDF)</a>;上面也列出了几个参考实现. 现在有Python, Java和Erlang, 还没有C#.<br>
这篇: <a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/">tutorial about how to implement Slope One in Python</a>是一个很好的怎么实现SlopeOne并使用它来推荐的例子. 但是现在好像不能访问了 :-(&nbsp; 参考这篇文章, 我会在下一篇用C#代码讲解怎么实现Weighted Slope One;<br>
<img src ="http://www.cnblogs.com/kuber/aggbug/1216846.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42811/" target="_blank">[新闻]2008年10月7日科技博客精选</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>Velocity, 微软的Memcached?!</title><link>http://www.cnblogs.com/kuber/archive/2008/06/04/1213348.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 04 Jun 2008 03:25:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/04/1213348.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1213348.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/04/1213348.html#Feedback</comments><slash:comments>34</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1213348.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1213348.html</trackback:ping><description><![CDATA[今天早上看LiveSino的RSS时发现了这条隐藏在"<a href="http://livesino.net/archives/915.live">TechEd 2008 Developers: 新闻汇总</a>"的消息. 微软总算是推出了他们的分布式缓存(<span class="l"><span style="font-family: Arial;"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><span style="font-size: 10pt;">Distributed In-Memory Cache)</span></span></span></span></span>.<br />
现在asp.net中的cache是在本机的, 如果web farm中的每台机器都要维护自己的cache, 最常用的cacheitem在每台server上都有一个copy.这样不仅浪费内存, 而且存在可能存在不同步的问题;Distributed cache解决了这个问题. 除了大型的企业应用, 在web2.0网站中Distributed cache也被广泛应用,以解决伸缩性问题. 如著名的开源软件Memcached被很多大的网站象WikiPedia , SlashDot用到;关于Distributed cache,可以google一下Memcached, 能找到很多介绍. <br />
<br />
微软推出了Velocity(code name), 目前还是CTP1, 我google了一下, 资料也很少, 主要是这两个:<br />
Velocity Team Blog: http://blogs.msdn.com/velocity/<br />
.net Developers Journal: http://dotnetaddict.dotnetdevelopersjournal.com/velocity_introduction.htm<br />
<br />
主要情况总结如下:<br />
<ol>
    <li>会作为Windows Service运行. 可以集群, 运行在几台Cache Server在</li>
    <li>通讯走TCP</li>
    <li>调用Add, Put, Get方法读/写缓存, 你可以缓存任何可以序列化的.net对象</li>
    <li>除了Key-Based fetching以外, 一个很酷的功能是可以使用tag 提取缓存对象集. </li>
    <li>据Team Blog所说, Velocity的目标不仅仅是为了asp.net开发, 甚至不仅仅是.net应用, 比如说非.net的IIS应用, windows Service等</li>
    <li>一个目前还没有但被广泛要求的功能是Push(notification, 消息通知), Cached Item被修改了之后, 通知使用它的代码. Velocity Team说这是他们下一步要关注的(Push-based notifications is a request we&#8217;ve heard from many folks. This is certainly an area we&#8217;re looking very deeply into.)</li>
    <li>目前是单独的产品, 据说是免费, 未来估计会集成到.net framework里面去</li>
</ol>
<img src ="http://www.cnblogs.com/kuber/aggbug/1213348.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/42809/" target="_blank">[新闻]51.COM技术副总裁邵辉跳槽百度</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item></channel></rss>