Tug of war.  Seattle, Washington.

第三章: 可扩展的网上社区系统

 

菲立.格林斯宾    著 /《网上出版指南》的一部份


随着社会的进步和物质财富的丰富,人们不必把时间都用来为生活奔波,越来越多的时间可以用在教育上。除却在学校的教室里的学习及其他常规的教育服务外,更大部分的学习其实是在一些非传统的场合。

没有人把密歇根民兵团(Michigan Militia militia.gen.mi.us)看成一个初等教育机构。但是每一个新成员都必须学习纪律条例,学习宪法,战地联络技巧,火器安全知识和射击术。谁想在这样的团体里崭露头角,谁就必须学习如何领导和教育其它的成员。

设想一下,假如你打算养一只狗。你必须了解不同品种狗的特性。在你选定一个品种以后,你还必须向周围有经验的饲养者讨教。如果你养的是小狗的话,你还得学习如何训练它,并且为它找一个好一点的兽医。什么牌子的狗食好,在那可以买到,这你心里也得有数。除此之外,你还得知道在哪里可以安全合法的松开它的链子,让它尽情的和其它的狗一起玩耍。事实上,这些相关的知识都是在一些闲谈中从一些有经验的饲养者那里获得的,他们却从来没有想过开个培训班,收点钱什么的。

如果你刚加入一家大的计算机公司工作,老职员们就会告诉你水冷却器在哪儿,告诉你即将从事的工作的重要性和目前已经完成了多少,教给你怎样使用开发工具,演示你将要使用到的关系型数据库管理系统。

什么是社区?

从上面的例子中可以归纳得到一些社区的共性。社区是由一些有着不同程度经验的人组成,并且那些专家总是乐于把自己的经验传授给新手。

这种社区的定义其中也包含了实际的大学校园。教授和博士生们传授知识给尚未毕业的本科生,直到他们毕业。这个定义并不完全包含“社区”这个词的通常含义--比如意义上的小镇或是城市里面的邻居。新搬进小区来的住户,固然需要知道附近的超级市场在哪里,但除此之外,未必都对邻居所追求的什么样的生活目标感兴趣。

我们要网上社区干什么?

如果你曾经漫步于牛津美丽的校园或是曼哈顿令人震惊的摩天大楼丛中,你一定要问为网上社区有什么用。我们正生活在真实的物质世界中,为什么还要一个电子的幻像?

一个重要原因是并不是所有的人都可以踏足他们所渴望到的地方。许多人渴望到常春藤联盟大学学习,但是他们付不起学费。虽然有些人可以付的起,但是4年没有工作也让他们有点吃不消。另外一些人想学习,可是由于他们的职责或是天生残疾的缘故,无法到学校去。

商业机构总可以得到他们想要的东西。他们当然可以花很多钱去建造豪华的办公室。二十一世纪都快要来了,但是人们的工作环境和百多年前的还是大同小异。上班族们每天早晨准时来到办公室,处理文件。假如采用先进的技术和管理方法,商业机构或许可以有效的雇佣在自己家里办事的帮工,使得进行中的工程项目或许都可以有专用的房间,项目团队有了固定的合作地点,毋须来回于各自的办公室,更毋须在办公室的旧纸堆里搜寻热点文件,项目的进度就可以更迅速了。

如果你还仍然坚持认为真实的社区应该比电子的网络社区重要,那我就要请你好好想一想初中的情况。

除了他们的父母选择的住所都比较近以外,初中里面的孩子再没有什么共同点。除非你的适应能力很强,找到个志趣相投的朋友的确是一件难事。高中的情况也大概是这样,但是由于人数比较多,找到志趣相投的朋友的机会可能会大一些。到了大学,不仅仅是人多了,而且个性的类型也较为集中。计算机痴们在加洲理工或是在MIT找到了同类;嘻皮士在Bard and Reed觅到了知音;高睿猫在Harvard和Princeton聚集;Colorado和Vermont则充满了酷爱滑雪的年轻人。大学毕业后,他们再也交不到如此之多的朋友。他们没有再和那样多的人来往,和公司里的同事固然要同心协力,尽力保住饭碗,但这一种共同的“兴趣”向来不足以促成亲密的关系。

不难看出,人们总是在周围的人很多,而且志趣相同的时候最容易交到挚友。联上因特网,我们能够与世界各地的朋友进行实时交流。除了那几个世界上最大的城市外,没有什么地方可以拥有如此规模的社区。既然在因特网上有如此巨大的通讯能力,拥有如此众多的未被发现的朋友,想交到一个精彩的朋友不难,你只需要一个能搜索和你有共同兴趣的朋友的方法,把他找出来,然后再找个能让你们合力协作的方法,和他结成伙伴。

总的来说,因特网的网上社区给我们带来以下的新事物:

这些都是原则上太多的事情可以在网上社区内实现。要实践的话,就要开发一些软件,让网上社区能不断壮大而之余不失其效益。审视一下现实世界里的公共社区的发展里程,可见启发良多。

公共社区的发展过程

Lower Klamath National Wildlife Refuge
古代
人们从人际间交流和面对面的会议中得到信息。政府和商业利益对信息的影响非常有限。

现代
随着活字印刷技术的发明(一般我们认为是Johannes Gutenberg在1450年把印刷系统做了一些实际的改进,其实早在1041年,中国的毕升就已经发明活字印刷技术),信息的传播越来越受到政府和商业的控制。大众媒体中都避免发放令广告商不满意的舆论。政府则通过控制权力机关发放宣传。

初期的因特网
用户从ARPAnet和早期因特网得到的大部分信息是有关个人的--个人的电子邮件,从邮件列表发来的信件,讨论组信件,别人撰写的但是没有发表的文章,为了表达个人观点的程序等等。那时没有广告。很少有或者根本就没有商业的介入。人们从USENET的讨论组里得到有关克莱斯勒和丰田轿车的性能比较,这些信息来自于那些购买了这两种牌子轿车的人,而不是生产厂家的自我吹嘘。

Refinery. Richmond, California.
1998年的因特网
随着万维网服务的发展,因特网终于给商业机构的公共关系部门搞明白了。原本组织得最好使用率最高的万维网服务彻底给无处不在的横条广告和崭新的回佣协定腐蚀进去。早期因特网服务似乎还隐约可见的,但是他们的发展受到了遏制。在过去,你可以在USENET中rec.autos的讨论组里获得克莱斯勒和丰田轿车的相关信息。现在呢?没有多少人知道这些讨论被放到哪里去了。autos.yahoo.com不再仅仅是一个讨论组,它成为了最高一层的域名。你可以在rec.autos.makers.chrysler找到你需要的信息,但是你会很快厌倦检索每天出现的,超过100封的新信件,特别是其中还充斥着大量由汽车经销商,和一般商业广告商发来的广告(诸如“快速致富法”之类)。由于没有专门的人来组织内容,它变得越来越失去价值。你会更加愿意去autos.yahoo.com检索资料,那是一个公认管理优秀的站点(我就是通过那里的推荐连接购买了我现在的丰田子弹头轿车 的),唯一的缺点是有用的信息交互总是给大量的横条广告打断。With the Web, the Internet finally became comprehensible to

从上面的观察我们看出什么奥妙了呢--技术可以从根本上影响网上社区的类型和范围,少数人和大多数人,大众之间信息传递的广度。

大问题

Vermont 有很多人正营运着公共社区类的网站服务。他们大部分采用简单的单机软件包,来解决诸如公众论坛或是分类广告之类的组织问题。当此类的网站越来越受欢迎的时候,设计者不得不每周花上80个小时无报酬的工作去平息争论,剔除多余的分类广告,删除那些因某些用户的电子邮件地址失效而产生的警告,解答疑问,更新内容,增添新的内容来回答用户的提问等等。叫人赞叹的是,竟然有这么多的人乐于每周花上80个小时去帮助他们的网友。然而令人沮丧的是,每周80个小时似乎还是不够。

无论多么的投入和能干,无一个人可以承受由一个网站的发展而衍生出来的大量工作。

Vermont

网站设计者最常用的解决方法是将其演变成一个接受赞助业网站。用户们再次访问的时候会惊异的发现主页上多了6条内容模糊,而且与本站毫不相关的横幅广告。有了收入,至少解决了网站的扩展所需。越来越多的访问者意味着越来越多的访问次数,意味着越来越多的广告被浏览,也意味着越来越多的网站收入。网站的始创者可以雇人来处理讨论组内容管理或是客户服务等等事务。网站的收入用来雇作家和网站管理员协调工作。由于存在着商业的利益,网站的内容可能变的中庸和充满铜臭的气味,但是管它哪,至少我们在赚大钱!咳...... 实际上却是,几乎所有商业网上社区都在亏损,因为为每名新加入而额外增加的开支实在太大了。

企业内部的网络也需要扩展。如果因为每增加一位新雇员而雇用一位新的版面协调员,网络或系统管理员,那真是难以想象。但是企业内部的社区系统总得和公共社区系统一样严肃认真的对待。假如仍然有雇员需要电子邮件向人请教怎么使用企业内部网络的基本指令的话,就等于宣告了企业内部社区系统的彻底失败。通过用一个能自动备份整理讯息内容的网站来合作,不是应该更有效吗?

解决大问题的大办法

Adin California.

采用一个可选择配置的系统是明智的选择:

  1. 建立储存用户资料的数据库,记录联络方法以及个人信息的保密程度
  2. 用数据库来记录网站内容,提供资料的人以及他们之间的相互关系
  3. 跟踪记录每一篇文章的浏览者
  4. 跟踪记录是哪一个用户在使用着社区系统的资源
  5. 跟踪记录用户从何而来以及又选择哪个推荐链接离开
  6. 如果是商业网站,需要记录每个横条广告被谁浏览了,以及效果怎样
  7. 帮助网站的拥有者联系不同类型的用户

究竟这样做的最终目的是什么?我给自己的网站上定了如下的目标:

如前所述的这种由7个模块组成的软件系统,不但实际的设计费用很高,维护起来也很花钱。新的网上社区系统,仍然需要一个运行于后台的关系型数据库管理系统的支持,虽然无甚特别新颖功能的需要,然而购买和维护数据库的费用仍会很高(详见“选择一个关系型数据库” 一章)。

在设计者打算推出网上社区之前,很有必要回过头来思考一下,需要建立什么样的模块,如何与其他的设计者合作,有什么是可以买回来,或是必须买的等等,等等……

买还是自行设计?

Cedars Market.  Adin, California

要实现以上提到社区系统的最基本的功能,必然牵涉到以下的方面:

  1. 选择Windows NT 还是Unix作为操作系统
  2. 选择一个关系型数据库管理系统
  3. 选择一个网络/数据库集成工具
  4. 编写SQL数据模型
  5. 设计一个用户界面以实现需要的功能
  6. 编写动态的网页把检索到的内容镶嵌到SQL表格中(也就是设计处理业务的用户界面)


Monkeys conferring.  Audubon Zoo.  New Orleans, Louisiana.

假设一个设计者正确的做出以上的全部决策,做一个如同我1995年在 http://www.photo.net/photo/设计的网上社区(程序设计的相当成功,但也不是完美无缺,1998年的时候我重写了一遍,补充了些新的内容),仍要花费他6个月时间外加50万美圆的程序开发费用。 假如再加上考虑到管理层所投入的关注,加班费,机会成本等等,就一个操作系统,关系型数据库管理系统或是网络开发工具的决策,就要用去10万美圆成本--那些对SQL 一窍不通的经理们和推销员们会在会议室里高谈阔论到底哪一个数据库系统比较好, Oracle, Informix, Sybase, 或是DB2。

大多数的决策层很难做出正确的选择。实际上,他们连选择一个稳定可靠的网站平台也常常办不到。(请看看我在"Sites that are really databases?"一章内关于“费柴软件”的批评)。即便他们碰巧选择了一个合适的结构,那么接下来在制定数据库模块的过程里,肯定都要遗漏些什么的。并且注定要为自己网站的用户界面痛苦不已,不得不再雇上一堆的雇员来解决,直到有一天豁然开朗,明白了怎样建立一个简单明了的网站。

无法避免的情况是:大量的钱花了在程序设计上;计划跟不上变化;用户们被程序时不时出现的问题搞的精疲力竭。步步艰难,一如承接大型工程项目般劳累。

情况不会改善?那倒也不一定。我的看法是:基于网络服务器的软件产业将会沿着一条商业数据处理软件产业走过的道路发展。

商业数据处理的历史

Elephants photographed through grass, as though on safari 在60年代,为了进行商业数据处理,人们首先得购买一些“铁家伙”(大型主机)。然后雇程序员来设计我们现在称为数据库管理系统的软件。同一批程序员还要建立数据模型,和负责籍建立起的数据模型执行存储和查询的工作。

到了70年代,人们愿意购买现成的商业数据库管理系统和硬件平台。他们已经受够了自己的程序员开发出来的,充满了问题的专用数据库管理系统,并且还发现自己的数据库存储并没有和其他的成百上千用户有任何的不同。公司内部的程序设计人员的职责变成了设计数据模型,和写点应用程序。

到了90年代,人们购买的是整套的企业软件系统,例如SAP或是Oracle Financials。然后买一个关系型数据库管理系统的产品来支持它。最后再装备支持关系型数据库管理系统的硬件。公司的程序员只是对数据模型和应用程序做一些适应需要的定制工作。

经过40年的发展,不难发现,有一个巨大的力量促使着硬件提供商逐渐变成数据模型/应用软件商的转变。有远见的公司意识到并且适应了这种变化。举例来说,IBM先是把重点转向了数据库管理系统,既而又转到了商业应用程序的开发上。也许有一天,当你连到Oracle的网站的时候,你可能不会想起他们以前做过数据库管理系统--全部的页面都在大谈特谈如何发展正在销售的包装好的商业工具。相反,有些硬件或是数据库公司就不是那么的顺应潮流,Digital和Sybase在这场转变中就差点给要了老命。

为什么会出现一个从定制程序设计向软件程序包的大转变哪?

South Island, New Zealand

既然那些管理人员自诩富有创造力,为什么他们仍乐意一窝蜂地使用着同样的软件系统?采用定制编写的软件,不是既符合本行业产品的特色,又可以按照自己的意愿向消费者和客户提供与众不同的服务吗?答案之一是,今天流行的程序开发工具比起60年代并没有多大的改进,但是对系统的要求却越来越复杂,所以开发定制的软件变得耗钱,而且没有保障。答案之二是,管理人员给软件设计预算的费用太少,以致于只有蠢材和懒人会当上这样的程序员,使得开发定制的软件变得更加耗钱,更加没有保障。答案之三是,那些商业管理人员并不比一群咩咩叫的绵羊聪明到那里去。他们看同样的商业书籍,以同样的方式思考。所以正如他们不能为公司设计文字处理软件一样,他们也无法设计出一套适合本公司的客户信息系统。

也许上面的理由兼而有之。但是不论怎么说,如果你的公司在管理薪水上采用的是和Wombley's Widgets公司一样的方式,而且Wombley's Widgets已经有一套现成的好软件来应付薪水管理,那么,你也采用Wombley's Widgets的软件就好了。如果你雇一些程序员来重新开发一套新的系统的话,乐观的情况下,你花了钱,并且得到了一套可以工作的系统。而在通常的情况则是,你得花几年时间和数以万计的钱来解决Wombley's Widgets早在几年前就已经解决了的问题。更糟糕的(也是令人惊异的普遍的)情况是,尽管你已经花了10年的时间和数不清的钱,最终还是一无所获,不得不放弃了原来的计划。

网络的情况又是怎样?

Chicks at the New Jersey State Fair 1995.  Flemington, New Jersey.

在网络发展的初期,网络出版者的装备通常是一台运行Unix操作系统的台式计算机。然后雇上几个程序员用Perl编写CGI脚本,从自己构造的数据库里存取资料。也就是说,数据库管理系统是他们自己设计的。到了1995年,网络出版者发现这样设计出来的程序往往有着千奇百怪的问题,比如,如果两个用户同时访问,那个可怜的小数据库将会崩溃。 所以出版者们开始采用标准的关系型数据库管理系统,比如Oracle,又回到了70年代商业数据处理的状况。这种情况或多或少的持续到了1998年8月,我写这一章的时候。

程序包方案?

能不能象文字处理软件那样,设计一整套网络出版的软件,然后出售?可行与否,就得看你的聪明的程度了。假设我们现在有一张装有“企业级软件系统”的光盘,下面是两种截然不同的描述:

程序设计者的描述 市场部的描述
这仅仅是一个我们在为15家公司做过数据处理系统之后一个程序的合集。很抱歉,我们从来没有真正的完成过,而且它并不能提供所有您想要的功能。可能在这些程序真正能够运转之前,还需要用50个程序员一年的时间来解决程序中无处不在的漏洞。尽管如此,我们可以保证,这样做带来的问题远比您从新设计一个系统要少的多。 这是一套设计合理,坚不可摧的商用数据处理系统,已经被15家先进的大公司所采用。 您的任何需要都可以得到满足。并且优异的扩展性能使得您只需花50个程序员一年的时间就可以解决针对您的特殊商业需要定制的问题。



谁的描述比较恰当?也许两者都是。但是哪一个将会给你带来3千5百万美圆的版权收入外加1亿美圆的的咨询费用?

ArsDigita的网上社区系统

Bernese Mountain Dog and Labrador.  Seattle, Washington.

写这样的一本书潜伏着一个危险--作者可能开始越来越坚信自己的理论:我实际上已经建立了一个包装好了的网上社区系统,并且是和Tracy Adams,Ben Adida,以及 Jin Choi一同完成的(确切点应该说是“重建”,很多子系统是在1995到1996年间设计完成的)这章提到的系统可以在。arsdigita.com. 免费的下载到源代码

即便是你打算自己重新设计一套系统,而不是下载我们的源代码,我也希望这章能给您提供一些帮助。

基本准则

ArsDigita的网上社区系统是建立在Oracle 8关系型数据库管理系统之上的,通过AOLserver Tcl API与因特网相连。目前,这种结构可以应付每秒超过100次的访问请求(America Online采用类似的结构AOLserver + Sybase + Unix每天成功的处理着上亿次的访问请求。)

我正在寻找愿意将该系统移植到微软的Active Server Pages系统或是移植到一个容易管理的solid关系型数据库管理系统之上的搭档。除此之外,要设计一个在其他任何网络服务系统,和其他任何关系型数据库管理系统运行的网上社区系统,的确太耗费时间了。我认为网络出版者没有必要过分关注于操作系统和数据库系统,更重要的是网站的数据模型和设计理念。最好的是赶紧选择一个已知经过考验的结构,然后把工作的重点迅速返回到商业决策的正轨。

冒着疏远一般的读者的危险,我们谈谈ArsDigita网上社区系统的七大模块:

  1. 用户数据库
  2. 内容数据库
  3. 用户/内容相关记录
  4. 会员价值
  5. 推荐/点击链接
  6. 横幅广告
  7. 出版者/会员之间的联系

在书的这么一开始,我就要跟你们来SQL结构化查询语言,真是觉得有点唐突,但是要想把数据结构表达的清楚,还是得靠它。没有一个精确的数据结构,要表达清楚什么是不可能的。如果你不是一个程序员,而且不清楚数据库中“表”的概念,那么请你跳到数据库一章,读一下那里关于数据库和SQL的简短介绍,然后再回来看下面的内容。

模块1:用户数据库

这是ArsDigita网上社区系统最核心的部分。所有其他模块的表都要和用户表联系:

create table users (
	user_id			integer not null primary key,
	first_names		varchar(100) not null,
	last_name		varchar(100) not null,
	priv_name		integer default 0,
	email			varchar(100) not null unique,
	priv_email		integer default 5,
	email_bouncing_p	char(1) default 'f' 
                                check(email_bouncing_p in ('t','f')),
        password		varchar(30) not null,
	url			varchar(200),
	on_vacation_until	date,
	last_visit		date,
	second_to_last_visit	date,
	registration_date	date
);

首先留意在整个社区数据模型中到处出现的隐私属性字段。对每一个从会员那里得到的资料,都有一个与之对应的隐私属性列,开头用“priv_”标记。隐私等级由0到9的数字刻画。

在用户表中,电子邮件和姓名列都有相对应的隐私属性字段。电子邮件地址的隐私属性确省值是“只给登记过的会员看”。如此便防止了(SPAM crawlers)从公共网站上收罗电子邮件地址。

除了有专门的字段记录用户的名字以外,我们还为记录用户个人主页的URL提供了空间。系统在显示该用户名字的同时,用一个超链接指向他的个人主页。 Salt Ash Inn.  Vermont

社区网站的用户中,假如有些会弄电子的程序员的话,就总会有某几个角落给设定了自动发电子邮件的情况。比如,一个电子邮件地址为joe_56K@aol.com的用户可以要求我的photo.net服务器,当有其他的用户上载了一个包含有“Linhof”字样的分类广告时,就发电子邮件通知他。Linhof是一个价值8000美圆的照相机,好的摄影师一天也只能用它拍两张照片,所以知道它的人不多。在这个用户的要求提出以后一个月,服务器开始第一次发现了含有“Linhof”字样的广告。在这个时候,这用户却刚刚更换了自己的调制解调器,选择了一个cable modem,因而邮件地址也相应的由joe_56K@aol.com might变成了joe_wayfast@mediaone.net。美国在线(America Online)不会替离开了的用户转发电子邮件,这样一来发给joe_56K@aol.com的信件将会被退回,我也不得不手动删除这个无效的请求。在1995年我设计这套软件的时候,这种工作并不是很重,但是到了1998,在我的数据库里记录着数以千计的这样的服务请求,有时,我的信箱里甚至堆积着好几十封的退回信。

由此可见,把退回的电子邮件都给管理员,不是一个适合不同大小规模社区的系统的做法。

因此在新程序里,添加了一个email_bouncing_p的标志量。末尾的“_p”表示这个字段的取值只是“是”或“否”。不幸的是,Oracle 8.0里并没有逻辑型变量,我不得不用“t”“f”来表示“是”“否”。开始的确省值是“否”。每一个送出去的电子邮件都被登记上,一旦出现退件的情况,给退回的邮件由一个Perl程序登记处理,并同时翻查记录,看看是否过去十天来发给这用户的电子邮件都打了回头。如果是这样,用户的email_bouncing_p将变成“是”,并且不再发电子邮件给该用户,直到他再次造访我的网站检验或是更改他的电子邮件地址。为什么设定10天,而不是5天?如果用户是每周才检查一次邮件,你总得照顾他的服务器有可能刚好在他检查邮件的时候打嗝吧。

如果会员告诉系统他要去渡假,在on_vacation_until字段里就会记录下他预计回来的日期。这样,在他回来的时候,就不会发现信箱里堆满了过时无用的信件。.

在网上社区里,有时候我们会想把“上次访问以后新发表的文章”同“已经阅读的文章”区别开来。很显然,仅仅增加一个last_visit字段是不够的。假设,每当用户造访时,ArsDigita网上社区系统就立即在last_visit字段里记录下日期和时间。由于HTTP是一个无连接的网络通讯协议,所以当用户点击超链接去阅读讨论区的文章的时候,ArsDigita网上社区系统又会再一次的查询用户数据库,发现该用户3秒钟以前刚刚访问过本站,于是,系统错误的以为在该用户最近的一次访问以来,没有新的文章发表。

ArsDigita网上社区系统采用last_visit和second_to_last_visit两个字段来记录用户的动作。我们利用了AOLserver的过滤器工具编制了一个Tcl程序,在每一个请求被响应以前它要先执行以下的程序:

如果请求是连着一个带有用户编号的cookie程序,而其中的last_visit字段既不是现在,也不是一天以前,那么过滤程序将在AOLserver输出的报头里,改变cookie中last_visit为现在的时间。同时在Oracle数据库里做以下的改动。

last_visit = sysdate, 
second_to_last_visit = last_visit

We set a persistent second_to_last_visit cookie with the last_visit time, either from the last_visit cookie or, if that wasn't present, with the value we just put into the second_to_last_visit column of the database.

对与那些没有注册的用户我们也是一样的对待,只不过只是在用户浏览器的cookies里做记录,而不是在服务器端的数据库里,

如果你是负责一个关系型数据库的话,那么你的网站就应该提供多种的个人化设定的服务。我们可以从一个简单普通的表开始:

create table users_preferences (
	user_id			integer not null references users,
	prefer_text_only_p	char(1) default 'f' check (prefer_text_only_p in ('t','f'))
);

网络出版者可以在这个表的基础上适当的添加更加合适的字段。

这个模块还要包括用户统计表(users_demographics)和用户联系表(users_contact)。如果想知道用户的年龄,性别,收入,家庭住址,通讯地址和电话号码,那就记录在这些表里好了。理所当然的在他们第一次注册的时候要求输入即可。可是,如果某女士只是想到这个网站看了一篇文章,有兴趣写几句评论,在她点击了“写评论”的超链接之后,浏览器里出现的登记新用户的页面就仿佛迎面向她泼去一盆冷水。如果要是在登记页面里询问多余姓名和电子邮件地址以外更多的资料,还怕她不马上跑掉?

ArsDigita网上社区系统采用循序渐进的方法获得用户的个人资料--可以指定在第十次访问的时候询问用户的年龄和性别,在第20次的时候,如果此前还没有询问过相关的信息(也许因为之前用户的访问都用了来执行网上购物的交互上),系统就会要求输入地址和电话号码。

模块2:内容数据库

在一个社区网站内好些地方我们需要用到内容数据库模块:

凭直觉行事的管理员会立即行动,把HTML文件一股脑的全部倒入数据库,心想从此以后,文件的源信息都唾手可得,网站内容的管理更不是问题了。有很多的商业网站正是这样进行内容管理的。要修改内容的话,都填张表格送过去好了。但是这样的系统有很多的问题。首先,虽然Netscape Navigator是一个很好的浏览器,但是有很多的文本编辑器要比它的HTML TEXTAREA好用的多。不仅是因为在Netscape TEXTAREA里编辑网页很不方便,而且我还发现Netscape 4.0 TEXTAREA里的字符数不能超过33,000。可是我的网站里很多文档远比这要长的多。比如,前一章 。http://www.photo.net/wtr/thebook/money.html)就大约有22,000个字。就更别说我每天要在GNU Emacs(一个文本编辑器)里查阅有大约8亿个字符的服务器记录文件了。

通常由操作系统(比如Unix, Windows, 或者Macintosh)提供的文件系统并不适合做管理数据库的工具,反而不少客户软件却可以做到。例如,在Unix文件系统下的数据可以如下处理:

喜欢搅作的朋友总要爱上自己发明的独特的网站内容管理系统,都没空去考虑如何在系统运作时执行如上的数据处理工作。

我没有精力为所有的网站都写一个数据库接口。所以我崭新的内容管理系统采用的不过是老而弥坚的Unix文件系统。静态的超文本文档仍然一如既往的存在于层次结构的文件系统中。ArsDigita网上社区系统采用关系型数据库来管理静态的网页的记录,和附加在这些静态网页之上的新内容(比如,评论)。这样做的一个好处是可靠。我让AOLserver把Unix文件系统中的静态网页勾出,然后连接数据库,取出附加的评论和链接一起发布给用户。但是,如果连接不到Oracle数据库,那么AOLserver的线程就仅是把文件系统中的内容传送给用户便是了。

即便是存在于Unix文件系统中的内容没有任何的改变,我们仍需要一个能记录下各种变化的关系型数据表:

create table static_pages (
	page_id		integer not null primary key,
	url_stub	varchar(400) not null unique,
	original_author	integer references users(user_id),
	-- generally PAGE_TITLE will be whatever was inside HTML TITLE tag
	page_title	varchar(4000),
	-- the dreaded CLOB data type; we're forced to use 
	-- in Oracle when we want strings longer than 4000 characters
	page_body	clob,
	draft_p		char(1) default 'f' check (draft_p in ('t','f')),
	-- force people to register before viewing?
	members_only_p	char(1) default 'f' check (members_only_p in ('t','f')),
	-- if we want to charge (or pay) readers for viewing this
	price		number,
	-- for deviations from site-default copyright policy
	copyright_info	varchar(4000),
	-- whether or not this page accepts reader contributions
	accept_comments_p	char(1) default 't' check (accept_comments_p in ('t','f')),
	accept_links_p		char(1) default 't' check (accept_links_p in ('t','f'))
);

在这张表里,我们采用一个整数型的页面号码(page_id)作为索引。当然也可以采用 url_stub(也即文件名)做索引,只是这样做会使得在Unix文件系统下重新整理文件变得十分困难。(在网站服务器上,要重新整理文件的时候应该很少;而且这样会令人家网站进来的链接都失效。)

在讨论完了怎么样把页面存储在Unix文件系统中之后,我们把页面的内容一股脑的塞到page_body字段里。为什么要这样做?那是因为把网站的内容放入数据库之后,就可以利用关系型数据库的全文搜索引擎(参见“数据库管理系统”一章)。无论你想要搜索的是页面的内容,标题,还是评论,都可以使用同样的方式轻而易举的实现。这样做的另一个好处就是,ACS可以很方地便为客户提供“内容如有变化,请立即通知”的服务。we stuff the full content into the page_body anyway. Why?

如果某个页面的draft_p属性被标记过,那么这个页面对所有除了作者以外的其他用户均是不可见的。同时在Unix文件系统里我们用“.draft.html”作为扩展名,以区别于普通的“.html”的文件。

如果有一个文件的扩展名是“.new.html”,那么就是说,这是原文件的新版本。只有原文的作者才有权力撰写新版本。我们通过以下的表格来记录原作者的信息:

create table static_page_authors (
	page_id		integer not null references static_pages,
	user_id		integer not null references users
);

如果打算帮助用户寻找他们感兴趣的新文章,那就必须对所有的文章进行分类。我们用一张表记录网站每个页面内容的类别,以便标记静态内容的类别,组织问与答讨论区,和记下用户的兴趣。

create table categories (
       category_id       integer not null primary key,
       category		 varchar(50)
);

We then reference this table from a table that maps static pages to categories:

create table static_categories (
	page_id		integer not null references static_pages,
	category_id	integer not null references categories,
	unique(page_id, category_id)
);

SQL高手会注意到unique字段的唯一性限制,可以避免同一页被多次分类。

通过分析服务器静态文件HEADs中META标记内的内容,我们可以让服务器自动为全网站的内容都填写上面的表格。

ArsDigita网上社区系统也会把读者的评论收集在静态的网页之中。这样做的一个很重要的目的是收集那些不同于原作者的观点和看法。但是,我们也需要了解读者是不是喜爱看这样的文章。为了这个目的,我们把读者的评论分为以下的几种:

标记为“另一个观点”的文章才都会列出来给读者看。假如你竟相信那些搞咨询过滤软件开发的人的话,你会想评级分数这东西应该很有用。但是我在photo.net的经验则告诉我不是如此。我曾经在18月里,收到了数以千计的评论,只有632个用户给了评分,尽管填写一个数字远比写一篇评论(平均900个字长)简单和快得多。你又会想应该让用户多看评级分数高的网页,评级低的交给管理员处理。但实际上这并不恰当。我的网站的平均得分是8.27。得分几乎接近10的是我那篇Graceland之旅 (http://www.photo.net/summer94/graceland.html,几乎没有人不会对它有兴趣,除了 那些已经去过那里的Elvis迷们。收到最多零分评级的是那篇理工科就业指南(http://www.photo.net/philg/careers.html),,如此一篇东西根本不应该有什么读者。为什么竟会收到这么多意见?一个愿意通过在网站上的表格对网站进行打分的人,一般不会发一些“多么好的网站啊”之类无聊电子邮件给出版者的。虽然这些信件会给你带来成就感,但是日子久了,要回应这种电子邮件就会变得很麻烦。The average rating of a

下面是支持这种系统的数据模型:

create table comments (
	page_id		integer not null references static_pages,
	user_id		integer not null references users,
	comment_type	varchar(30),
	message		clob,
	--comment_type值不是‘评级’的话,设为null
	rating		integer check (rating >= 0 and rating <= 10), originating_ip varchar(50), posting_time date ); 

在评论被加入的时候,我们同时也记录下用户的IP地址。有人恶意的加入很多不好的评论,一般都可以通过检索用户名来删除他的文章。但是,有些入侵者,有很多的帐号,能籍检索IP地址来删除文章也是有用的。

另一个用户提供网站内容的方式是相关的超链接。从某种程度上来说,每一个网上社区系统就是一个小型的Yahoo。作者和读者在因特网上发现了相关的网站之后,可以在这里介绍给大家。通过一个自动小工具,网站出版者就可以不用再处理大批“请将我的网站链接加入”的请求。把超链接记录在一个结构化的数据库里,只消运行一个链接检查小程序,就能够拣出无效的链接,并将它们删除。

下面是数据结构:

create table links (
	page_id		integer not null references static_pages,
	user_id		integer not null references users,
	url		varchar(300) not null,
	link_title	varchar(100) not null,
	link_description	varchar(4000),
	-- contact if link is dead?
	contact_p	char(1) default 't' check (contact_p in ('t','f')),
	status		char(10) default 'live' check (status in ('live','coma','dead','removed')),
	originating_ip	varchar(50),
	posting_time	date,
	unique(page_id,url)
);

如果阿祖在Geocities上申请了一个存放自己主页的空间,虽然目前主页的全部内容还只是一个“正在建设中”动态图象,但是他认为这是一个与你网站内容相关的链接。在他把这个链接加入以后,那些要求通知网页变化的作者就会收到系统自动发来的电子邮件。网页的作者和系统管理员都可以看到有关该链接的简介和评论等等,如果他们认为此链接不合适,就删除之。

如果阿潘把他的商业站点的链接添加到你网站的每一个页面之中,你怎么办?为了对付这样的情况,我们得准备一份“黑名单”:

create table link_kill_patterns (
	page_id		integer references static_pages,
	-- who added the kill pattern
	user_id		integer not null references users,
	date_added	date,
	glob_pattern	varchar(500) not null
);

在黑名单的glob_pattern字段里加入一个链接,比如*microsoft.com*, 这样链接数据库中凡是与之匹配的超链接,包括那些使用此地址的所有页面链接,都会被删除。并且,以后凡是企图加入此超链接的请求都会被系统自动的拒绝。

有了相关链接和评论,我们就有了记录与静态网页紧密相关的,用户投稿的所有相关信息。对于一个标准的网上社区系统,还必须考虑用户间的联系,虽然这与静态网页的联系不是那么的紧密。比如,在我的私人网站上,我有大概1000个超文本页面,但是只有区区6个问与答讨论区,却都是我最喜爱的讨论组。photo.net讨论组里有一些问题与网站内关于摄影技巧的静态网页有很清晰的联系,而其中的大部分则是来自于读者平日积累起来的个人经验。用户的回答常常会变得和网站内容越来越不相干了。

单单是讨论数据模型和数据库支持下的多线程讨论系统,就需要花去一整章的篇幅。因此我建议您可以去http://www.photo.net/photo/的用户论坛看看,体会一下来自其它人的经验。或者去看看我前一本书的第13章( http://www.photo.net/wtr/dead-trees/53013.htm,那里有关于数据模型和软件的介绍。

用户间的联系的另一种形式是分类广告。这里的“分类广告”的概念不能单纯的理解为“一个为了出卖某物品的告示”,而应该衍生为“用户撰写的与主题内容无关的文章,目的一般不是为了展开一个广泛的话题(只是为了吸引少数人的注意),并且此类的文章一般是可以被分类的。”

在ACS的分类广告系统中,可以实现下述的功能:

当然,有些出版者也把分类广告系统用在了狭义的用途上:方便用户出售物品给其它的人。用户不免要产生“怎么知道谁是可以信赖的”询问。在photo.net,用户可以从“左临右舍”的服务中寻求帮助。籍分类广告成功购买或是出售过什么的人,我们都鼓励他们做个记录在网站上。到目前为止,数据库里存有320条这样的记录。但是分类广告却有万条之多。与其让用户输入自己的经历,为什么不聪明一点,好好利用数据库里的数据?不错,买者最想知道的一件事是卖家是不是一个专业照相机经销商。大家一般都认为照相机经销商的价格高,而且服务很敷衍,但如果是一个摄影师想出售他的闲置设备,那情况好的多了。可是我们并没有询问每一个发布广告的人是否是照相机经销商啊?即便这么做了,我们有没有足够的人手去核实这些哪?

经销商和个人卖家的区别在哪儿呢?看他发表过的东西。ArsDigita网上社区系统在个人会员的简介中有一个包含了以下的几个超链接的页面:

一般来说经销商发表的除了大量分类广告之外就不会有太多其他东西: .

我碰巧就知道一位名叫Russ Arcuri的先生,他不是一位照相机经销商。每个看了他的个人介绍的人都会这么认为--在问与答论坛发表了430篇文章(自1996年12月开始),关于两篇静态文章的10篇评论,2篇“左临右舍”评论,和仅有的3个分类广告(请见http://www.photo.net/wtr/dead-trees/53013.htm)。

限于篇幅关系,这里就略去了有数据模型的内容,请大家参阅我上一本书的第13章(http://www.photo.net/wtr/dead-trees/53013.htm),在那里有关于如何建设一个网络分类拍卖系统的详细介绍。For brevity, the data model is omitted here because Chapter 13 of my last book ( gives detailed instructions for building a Web-based classifieds/auctioning system.

网上聊天在因特网上大受欢迎,但是怎么样和网络服务结合起来,的确有点困难。虽然我没有管理一个聊天服务器的经验,但是在商业网站系统管理员邮件列表中,我看到了太多的标题为“聊天服务器垮了”的信件。并且我认为,在人们安装了那些即时网上消息发送软件之后,很难想象他们会再去下载客户端程序或者是使用笨拙的Java小程序。广受欢迎的ICQ,其强大的客户程序本身就具有充当聊天服务器的功能。AIM(America Online's instant messaging system)以附了在网景公司的导航者浏览器上,到处风行。它不仅 可以为两个同时在因特网上的用户提供服务,而且毫不费劲就可以接触到1千1百万的AOL(美国在线)的用户。但是AIM目前还不支持多用户聊天。在ICQ和AOL里,不容易找到用户自设的别名。所以我们在users_contact表中添加了aim_screen_name和icq_number字段。我们可以利用这些资料帮助注册了的用户通过其他平台进行交谈。

更有趣的是,从技术上说,把从普通网站上产生的短消息发送到AOL或是ICQ的网络中并不难以实现。如果你的网站能发出即时的信息,那么用户一般从通过电子邮件获得的信息可以选择用AIM接收。

聊天并不是很困难,只是很难想象为什么要在网上社区里加入这个功能,除非你的网站需要做产品的远程支持服务。在这样的情况下,聊天软件可以大大缩短网站技术人员和用户之间的距离。比如说你的产品是计算机软件,聊天系统可以使你的技术人员在某一程度上远程操作软件,技术人员通过网页演示容易使人糊涂的地方,并且给一些声音和文字的指导。

别忘了,在众多的聊天“科技”的宣传中,并没有人阻止你安装一个IRC给你的用户们使用啊(请见 http://www.yahoo.com/Computers_and_Internet/Internet/Chat/IRC/)。

模块3: 用户/内容索引

了解每一个用户都读过什么内容,对一个打算帮助新手的专家来说非常有用。这不同于在“用户追踪”一章里提到的网络活动总计。仔细的在数据库里记录用户的每一个举动将给网站服务器带来巨大的负担,所以我们必须在确有需要的情况下才做记录,尽可能的减小数据库的规模。

根本不用去考虑记录那些细枝末节的东西,我们应把注意力放在观察用户浏览页面的情况上。可是,即便是这样的统计量也会大得可怕。在1998年8月以前的17个月中,我的photo.net一共统计到了超过150万不同的浏览者。假设每一个浏览者平均看了20页不同的网页,这样就会产生3000万条记录。如果每条记录需要用去100个字(byte)的长度来储存,那么一共是3 GB的数据!在总共18GB的硬盘上,3GB似乎还不算什么。可是,如果查询和记录的过于频繁,所有的用户数据都必须放置在内存中。我的服务器只有4GB的内存,一下子要拿出75%的空间给这些数据,这不是在勒我的脖子吗!

如果抛开那些偶尔到访的网络冲浪者,在他们还没有成为登记会员之前不做任何的记录,情况又会怎么样?这样以来我的数据要求似乎才合理一些。在photo.net,曾经发表过评论,问与答文章,或是分类广告的用户,大概只有5万名。进一步假设,我们没有必要记录某个特定的用户甲访问了某个特定的页面乙几次。这样一来存储空间的要求就合理多了,尽管我们必须假设每个用户至少浏览100页,总共也只有500万条记录。每条记录100个字(byte),全部数据的大小变成了可以接受的500MB,但是这样大的内存在1998年6月的时候仍要花费2000美圆购置。

除了限制统计用户的数目以外,我们还可以限制统计网页的数目,来减少内存支出。一个象photo.net的网站有超过10万的文档,但是大多数是用户发表的小文章,比如分类广告和讨论文章。我们似乎从用户甲浏览了第35623号分类广告这样的一个事件中,得不到什么有价值的信息。何不把重点放在数量不足1000的静态网页之上呢?每一位用户只消用1000位(bit)的数据来标记他们读过的网页即可。举例来说,如果记录是是以“11001...”开始的,这就是意味着用户阅读了编号为1,2,和5的页面,而没有看过第3和第4页。利用这样的法则,只需要不到200MB的内存空间,我们就可以记录150万用户在1000页网站上的全部活动。

这样的做的缺点是什么呢?关系型数据库虽然可以把二进制的数据当作“大型二进制对象”(binary large objects (BLOBs))进行存储,但是这些数据不可以用来作为索引,尤其不可以通过SQL语言来查询,不可以通过标准工具生成报告等等。你会发现自己的程序很难移植去其他数据库系统。比如,要想是这样的想法在Oracle 8系统中实现,你必须痛苦的用Oracle特有的PL/SQL 编写一大堆的代码,然后用C或Java分别编写一些服务器端(Oracle 8.1),和在客户端(也就是AOLserver)运行的程序。

五花八门的网站活动统计和分析软件包,例如Andromedia's ARIA(http://www.andromedia.com)等等,令情况变得更复杂。在软件的新领域,比如网络出版,自己设计软件一般要比组装别人设计好的软件包来的简单。但是,因为我还未知道怎样做是最好的方式,所以我在设计ArsDigita网上社区系统的时候,把其他的模块对这个模块的依赖尽量减少。 ).

灵活和按原则的运作都很好,只是需要有人来写一些程序。下面是ACS的一些基本设定:

最后一点有一个例外。如果出版者打算提供向用户发送“你还没有看过的讨论组新发表文章简介”的电子邮件的话,就必须记录起码一星期的用户发表和下载的记录。

模块4: 会员价值

Yosemite Falls (lower).  Half an hour after sunset.  Yosemite National Park.  California 1992.

商业网站的出版者和管理员很关心用户究竟给他们会带来多少利润。非商业网站和因特网网上社区也必须了解哪些会员是有价值的,哪些会员只是给网站带来了负担。

即便是一个富有心计的贪婪的商业网站出版者,也很难对用户在网站上的活动做出一个合适的估价。人们一般还是愿意付钱在杂志上做广告。这样来看, 应该按每个广告收费。但是一旦你也安装了一个ArsDigita网上社区系统,其后让人们上载广告的费用几乎是0。如果有人到你的网站来看分类广告的同时,他也看了你的横幅广告,这样,你反倒会愿意付钱给那个上载分类广告的人!这看上去很合乎逻辑,但是一旦你考虑到每个上载分类广告的人都有可能增加如下的营运工作:(1)删除重复的广告 (2)编辑广告(3)为用户增加使用说明,包括那些你认为很容易明白的东西(4)处理给用户的退回的信件,等等。虽然我给ACS设计的分类广告系统以零运行费用为目标,但是实际上,在photo.net,每1000个上载的新的广告要耗费我30分钟的时间去整理。

在现实世界中,要按客户给你的麻烦多少定不同的收费是很困难的。 出版商总是要定出一个用户平等的收费,而且把客户服务的花费均摊他们身上。在网络的世界里,虽然似乎理解起来很困难,但是好象不存在一个合适的理由不按客户耗时计算收费,更何况这在技术上绝对可行。比如,我在报纸上登了一则广告,然后打电话去终止它,不会另外收费。但是,在网络世界里,一个用户发布了一个广告,然后打电话到你的客户服务部门请求终止,这可能要比单纯的发布一个广告要多耗费你100倍的时间。按照客户所消耗的服务时间收费是很合理的,令客户明白也不会太困难。

在现实的世界里,大家一致公认的是,所谓用户带来贡献的无非就是钱。如果简向自己的一位朋友推荐某个牌子的夹克很好,那么无论是生产者还是经销商都无从知晓。在网络世界里,用户的贡献是多种多样的:可以在网上社区里提供一个很有趣的问题,或者回答别人的询问,从那些给网站回佣的网上商店购买商品,撰写文章,或者是向自己的朋友推荐此网站(比如填写一些表格,之后让你的朋友会收到一份邀请光临的电子邮件)。

在公共网上社区里,即便在客户服务花费其实几乎为零的情况下,你可能仍打算按用户浏览的页面多少收费。要么是你过分贪婪, 要么是你得为你的网站内容支付高额的花费。ArsDigita网上社区系统允许你就每个页面定价格。价格可以是负的--籍此吸引用户浏览那些对你或是网站极为重要的信息。

ArsDigita网上社区系统并没有给网站设定赚钱方案。出版者不一定要无偿广播,不一定要公开网站,也不一定只让员工浏览。ACS的设定的是一套全面的按事件计算用户消费的框架。出版者决定是否和怎样向用户收费。出版者决定是否使用真正的“钱”,也即最终并不是要求用户掏钱。出版者决定是否需要在线的收费或者向一个现成的计费系统产生帐单。出版者还可以决定是定期收费哪,还是当用户达到一定值的时候作出行动。

下面是可收费的事件列表:

实际上的记费过程是由ArsDigita网上购物系统来处理的, 这在电子商务一章有详细的介绍。The actual billing of charge cards is handled by software lifted from

模块5: 推荐/点击链接

Elephant Seal Colony.  Just north of the Hearst Castle.  San Simeon, California.

一般来说,我们都希望毋须登记就可以浏览公共网站大部分的内容。但是为了避免购买几百公斤重的数据库服务器,应尽量减少记录没有登记的用户的信息。另一方面,我们又需要充足的数据来了解人们是从何处来访,继而又是通过我们网站的链接去往何处。

既然无法预知来访者的身份,只能用较为基本的方法记录外部推荐链接的资料。在用户请求访问被提交之后自动运行AOLserver的 Tcl过滤器。外部推荐链接的头信息,如果数据库里早有这链接的记录, 那么就将原先在referer_log表中的计数器加一:

create table referer_log (
	-- relative to the PageRoot, includes the leading /
	local_url	varchar(250) not null,
	-- full URL on the foreign server (including http://)
	foreign_url	varchar(250) not null,
	entry_date	date,	-- we count referrals per day
	click_count	integer default 0
);

下面是一个记录的具体例子:

local_url /photo/
foreign_url http://www.yahoo.com/Arts/Visual_Arts/Photography/Magazines/
entry_date 1998-06-12
click_count 24

以上的记录表明有24个访客是由Yahoo来photo.net的。但是用这方法来统计从AltaVista来的访客就不那么容易,因为每一个访问都衍生一个新记录:

local_url http://www.photo.net/photo/point-and-shoot-tips.html
foreign_url http://altavista.digital.com/cgi-bin/query?pg=q&kl=XX&q=point+and+shoot+photography+techniques
entry_date 1998-06-12
click_count 1

这里,在每一个推荐链接的头信息包含了有用户输入的不同的查询语句。如果要把这些记录合起来,必须采用通配符号,举例来说就是,

http://altavista.digital.com* 映射成为 http://altavista.digital.com 

只要在推荐链接的头信息里包含“http://altavista.digital.com”,就认为是由AltaVista而来。可以在以下的表中做记录:

create table referer_log_glob_patterns (
	glob_pattern		varchar(250) primary key,
	canonical_foreign_url	varchar(250)
);

由AOLserver每30分钟从数据库里读出来(放在内存里)。有意思的是,我们大概也会想看看用户是输入了什么查询字符串,才被带到这里来的。所以在glob_patterns表里我们增加了Tcl的表达式。如果不为空,过滤器就要在头信息内寻找用户输入的查询字符串:

create table referer_log_glob_patterns (
	glob_pattern		varchar(250) primary key,
	canonical_foreign_url	varchar(250),
	-- not NULL if this is here for a search engine and 
	-- we're also interested in harvesting query strings
	search_engine_name	varchar(30),
	search_engine_regexp	varchar(200)
);

-- 查询字符串是由用户输入的,既包括我们自己的搜索引擎,也包括其它网站的 

create table query_strings (
	query_date	date not null,
	query_string	varchar(300) not null,
	-- if they came in from a public search engine and we 
	-- picked it from the referer header
	search_engine_name	varchar(30),
	-- if we know who they are
	user_id		integer references users,
	-- not null if this was a local query
	n_results	integer	
);

当用户在本网站输入的查询没有结果的时候,最后这个表格(query_strings)就显得格外的重要。

跟踪连出网站的点击链接情况很相似。请阅读用户跟踪一章,那里面所讨论的系统自1996年以来一直没有变过。

模块6:横幅广告

Fish for sale in the Public Market, Seattle, Washington

在1995年的时候,横幅广告是因特网投资家梦想的摇钱树。但是现在没有人不讨厌看到他的。那为什么我们还要在ArsDigita网上社区系统里添加一个广告服务器呢?--毕竟看到出版者们花5万美圆买了一堆无法运转的破烂广告服务器,的确是一件很让人心痛的事情。

我们的5万美圆的广告服务器如下:

create table advs (
	adv_key		varchar(200) primary key,
	adv_filename	varchar(200),
	target_url	varchar(500)
);

create table adv_log (
	adv_key		varchar(200) not null references advs,	
	entry_date	date,
	display_count	integer default 0,
	click_count	integer default 0
);

在advs表里保存有横幅广告的图片和指向该网站的URL。adv_log表里记录每天横幅广告被显示和每天被点击的次数。在我对尼康300mm镜头的评论(http://www.photo.net/photo/nikon/300-2.8.html)中有一个这样的推荐链接:




只要advs表的内容正确,adimg.tcl程序就会送出一条GIF图,游说用户买横幅广告客户的货品了。当用户还在注视着广告的画面的时候,adimg程序继续在adv_log表里记录下显示的次数。一旦用户点击了广告画面,adhref.tcl程序就会把他带到http://www.pfizer.com。 adhref.tcl在此之后仍将继续运行,在adv_log表中记录下这次点击链接。

为了让1994年的市场总监们的梦想都可以变为事实,我们在广告服务器之上设置了广告的源数据的表及逻辑机制,就用户特征数据分析,自动向他们送出陌生但是可能感兴趣的广告。用户的兴趣特征是由全网站通用的categories表记录提供。要推算用户的兴趣特征,可以籍模块3(用户/内容索引)推算出来,也可以检查登记用户要求获得什么类型新内容的通知的users_interests表。

我们把用户/广告的历史记录在下面的表格里:

create table adv_user_map (
	adv_key		varchar(200) not null references advs,
	user_id		integer not null references users,
	event_time	date not null,
	-- will generally be 'd' (displayed) 'c' (clicked through)
	event_type	char(1)
);

我们只记录登记用户的信息,并不去关心那些突然到来的网上冲浪者。假设我们把adv_user_map和广告分类的数据进一步如下结合起来:

create table adv_categories (
	adv_key		varchar(200) not null references advs,
	category_id	integer not null references categories,
	unique(adv_key, category_id)
);

就可以回答:“用户甲有多大的可能性去点击一个保健产品的广告?”这一类问题。利用adv_categories里的数据,可以设计一个Tcl程序来实现“随机抽取保健品广告显示给该用户看”或者“把那些他没有看过的保健品广告显示给他”再或者,如果他已经看过所有的广告,那么就“给他看他见过次数最少的广告”。

这个模块包含大量需要密码才可以浏览的业务报告页面,一些是供出版者看的,另一些是给各个广告商的。

我见过的最有趣的一则横条广告是,1998年9月20号,CNN的NetGravity网站上显示了一个宝马牌轿车的横条广告,图片显示一辆宝马轿车飞驰过一片朦胧的大地,而下面显示的文章也确是有关轿车的:“约克郡女公爵的母亲死于车祸”

模块7: 出版者/会员之间的联系

MIT Graduation 1998

人们不辞劳苦的花很多的钱来建设网站的一个原因是,能够和用户/消费者直接的接触。在ArsDigita网上社区系统里可以实现以下的功能:

  1. 向出版者建议哪些用户应该得到提拔,比如从新手到合作管理员
  2. 允许出版者有选择的扩大会员组

MIT Graduation 1998

提升会员是ACS最巧妙的设计。每一个讨论组都可以发展成为一个独立的子社区。因此当简在户外摄影讨论组里回答了100个问题之后,就应该将其提升为合作管理员,而且这不并是说她也有能力可以做影楼摄影的合作管理员。也许在影楼摄影讨论组里,有人根本没有见过简写的文章哪!

可以从下面的这几个方面来考核会员是否有资格被提升:

这样你就可以要求:“给那些这个月在讨论组里发信超过10篇,但是尚未读过《和Samantha一起旅行》的会员”或者“给那些说过自己比较喜欢大型相机的人们发信”

最难的部分

Clean Room.  Microdisplay Corporation.

假设有人完成了前述的7个模块,就建设网络服务向前推进了一大步。这样困难的数据模型和程序都实现了, 很难想象还有什么更难的了。实际上,上面所介绍的只是一个框架,是人们真正需要的网络服务的一个开始。但这是一个很不错的开始,可以籍此收集足够数据,让出版者可以做一些有趣的分析。 下面是一个例子:

假设某个网站有1000个静态的超文本文件,一个讨论组,和上面所讲到的所有服务和信息。一个专家发现了这个网站,并且加入了进来,参与讨论,给静态的网页做评论。我希望能让系统自动的发现这个专家。如果这个专家问“我要如何加上第1001个静态文件,可以对网站的帮助最大?”我希望系统能给出点建议。

这几乎就是一个人工智能的问题,需要耗费一个卓越的计算机科学家几十年的时间来研究。

卓越的计算机科学家?就是那些把微软牌死机软件(Microsoft Blue Screen of Death)(TM)安装到你的计算机里, 然后告诉你最钟爱的电子商务站点“服务器没有响应”的人?或者是他们那些为香港造价200亿美圆的新机场设计程序的,令受困的乘客们不得不忍受同样遭遇的死鱼和烂水果的臭味的人?

也许,我们应该尝试让社区内的用户自己动手做一些程序的设计。大部分的可以买到的网络技术都认定一个框架--“我们设计的,就是用户们所需要的”,而就是这样的3层的模式毁了香港的新机场。ArsDigita网上社区系统,从另一方面说也是建立在这样的模式之上--真正难的问题都交给了标准的商业关系型数据库管理系统去解决。不难的东西都可以通过解释型的编程语言来实现,这样新手们都可以很容易修改和扩展这个软件。

如果我们够聪明,懂得设计出安全有效的语言,编写程序的权力就不会再是仅仅被网站的所有者所独占了。最富创意最实用的服务常常是在允许用户参与编程的服务器上,由用户编写提供算法。也就是诸如“在星期一和星期四的晚上,如果有我朋友朱迪的新文章,请发电子邮件通知我”的服务要求。

在本书的有关编程的章节里,将会阐述这种软件结构在电子商务和将要取代桌面应用软件的服务的优势和可靠性问题。

摘要

合作技术的使用可以改变人们工作,学习甚至生活的方式。例如,直到电话出现之前,大公司才只有区区几百人,甚至也只能工作在同一幢大楼里才可以进行。能有效支持网上社区的技术,将会改变人们的的工作习惯,甚至包括我们不经意的假定。

更多的信息





或者 浏览下一章:静态网站的发展.


philg@mit.edu
Add a comment | Add a link