INFORMATION_SCHEMA支持获取一个table中任意列的属性相关信息

http://dev.mysql.com/doc/refman/5.0/en/columns-table.html

SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT

FROM INFORMATION_SCHEMA.COLUMNS

WHERE table_name = ‘tbl_name’

[AND table_schema = ‘db_name’]

[AND column_name = ‘wild’]

可以通过上述语句获取指定列的DATA_TYPE与CHARACTER_MAXIMUM_LENGTH来确定一个列是否为varchar,以及支持的最大size

“一个tbdesc表中有一列append,类型为varchar”

mysql> SELECT DATA_TYPE,CHARACTER_MAXIMUM_LENGTH from INFORMATION_SCHEMA.COLUMNS  where table_name=’tbdesc’ and column_name = ‘append’;
+———–+————————–+
| DATA_TYPE | CHARACTER_MAXIMUM_LENGTH |
+———–+————————–+
| varchar   |                      512 |
+———–+————————–+

以下语句可以重新设置该列的maxsize

ALTER TABLE tbdesc MODIFY append varchar(2048)

,

Microsoft在2007年的文章中描述了他们用于维护大规模互联网服务的工具利器AutoPilot,采用简单的模型和设计思想,AutoPilot负责自动化的运维数据中心中提供服务的大规模机器。想起每次上线时的等待,尤其在部分模块启动时间很长的时候,必须到全部都部署完成并check完成后才能完事的痛苦过程,就感叹国外的先进生产力。原文pdf见这里

Design Principles

  1. 被autopilot管理的large-scale web service必须自身有一定的容错性,任何一个节点或者部分节点的失效都应该不影响系统对外的正常服务。autopilot是一个lazy action的监控&修复Service。
  2. Simplicity is as important as fault-tolerance when building a large-scale reliable, maintainable system。最近一年对这句话感触很深,一个本身就很庞大的系统,在很多地方必须尽可能的简单,任何过于精巧的实现解决的问题,一旦出了问题,很可能都会带来更严重的问题,并且很难处理。Autopilot在设计上的机制上非常简单,从错误分类、到执行的操作以及节点的状态定义都简单通用,不进行特化。同时允许用户端程序自己进行部分扩展。

单个Autopilot实例负责管理的一堆机器被成为一个cluster,数据中心中的购置的机器配置都是符合一系列标准套餐中的某种。

阅读全文…

周末阅读了下陈硕老师的分布式系统的工程化开发方法,原地址连接请猛击这里(blog, 视频),也将blog上的一页页演讲稿整理成了pdf借花献佛一下,点击这里下载。

在阅读完陈硕老师的演讲稿以及相关视频后,回顾了下自己工作一年来碰到的一些问题,梳理下一些设计中需要考虑的点。与陈硕老师的题目不同,这里主要针对大型互联网后台程序,存在模块间的交互,但部署同一个服务模块的不同机器之间的状态是一致的,因此不讨论分布式系统中常见一致性、通信、选举等问题。

  • Design for failure —— 大型互联网的后端服务是7*24 online service的,因此当出现异常时(单个或者多个节点异常,必须在尽可能保证服务的前提下,尽快恢复)
  • 能重启、快速重启 —— 一个服务启动的速度对该模块的日常更新,以及异常情况下的快速恢复有着决定性的作用,在开发时应该尽可能的缩短启动的时间,在完成必须启动和加载的相关配置后,优先提供服务。此外陈硕老师提到的优雅重启,也是需要考虑的问题,尽可能的减少停止服务重启时刻对现在正在service的请求造成的影响。
  • 避免阻塞 —— 对于多个模块通过tcp交互的场景,如果某个模块的工作线程被阻塞,则会导致上游不断的超时,甚至请求堆积到被阻塞的模块,因此需要尽可能的减少阻塞。可以通过设置合理的超时时间,调高工作线程数等方式。
  • 监控 —— 对于7*24 online的service尤为重要,最好能全方位的提供一个方便的探测当前模块服务状态的接口,unix文件系统都会预留proc这样的接口,可以观察正在运行的进程状态。这里的探测不仅仅包括常用的硬件如CPU、内存、网卡、句柄等探测,甚至包含与上下游交互的健康状态,以及其他业务相关的信息。
  • 操纵性 —— 除了监控,对于自己写的online service,在上线服务后,应该具备一定的可操控能力,例如运行时改变一些行为状态,避免异常时只能选择回滚。对于一些关键的功能点,应该有一些可运行时reload的开关控制,在特殊情况时进行操作。
  • 分步升级 —— 多个模块不可能同时升级,如果涉及接口的变动,采用C buffer传递字节信息会造成接口不兼容的依赖,考虑idl/protocol buffer。

————————分割线——————————扯点其他的————————————

在陈硕老师的PPT中提到了在epoll的水平触发(LT)方式下,accept返回EMFILE时的异常问题解决,自己实验了下,并没有持续返回可读,通过tcpdump查看,发现accept失败后,系统发送了FIN包主动断开的连接,怀疑与linux内核版本有关。可以查看下面tcpdump的数据。

阅读全文…

,

在实际中碰到这样一类问题,有一个结构体,中间包括各种不同的类型,但有一种函数,需要对不同类型字段的值都进行统计、排序等操作,函数中90%的代码都相同,唯一的不同是获取目标结构体的不同字段的值,为了避免针对不同类型的字段,声明不同类型的变量,通过封装get_field_val(struct)为模板函数解决此问题。如下代码

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct info_t{
 int a;
 string b;
 int c;
};

class account{
public:
 template<class T>
 void account_field(int type)
 {
 vector<T> vec;
 for(int i = 0; i < 8; i++)
 {
 T val;
 val = get_val<T>(infos[i], type);
 vec.push_back(val);
 }
 //统计, 排序xxxx一堆工作
 //...
 return;
 }

 template<class T>
 T get_val(info_t info, int type)
 {
 if(type == 1)
 return info.a;
 else
 return info.c;
 }

private:
 info_t infos[8];
};

template<> string account::get_val<string>(info_t info, int type)
{
 return info.b;
}

int main(void)
{
    account a;
    a.account_field<int>(1);
    a.account_field<string>(2);
    return 0;
}

如上,使用模板get_val函数和type获取指定字段的值,并且针对string进行模板的特化。对于类成员模板函数的特化,必须放在类定义的外部,否则会报Explicit specialization in non-namespace scope的错误,具体的原因可以参见如下说明。如果没有该特化,也可以直接重载一个函数,但这样就不能在调用函数时显示特化了,特别是对于调用a.account_field<T>(type)的函数。

An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member.

An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.

,

当我们需要对某段读写文件并进行处理的程序进行性能测试时,文件会被系统cache住从而影响I/O的效率,必须清理cache中的对应文件的才能正确的进行性能测试。通常清理内存可以采用下面的这条命令,但这条命令只有root才能使用,另外一方面这个会清理所有的cache,也许会影响其他程序的性能。

echo 3>/proc/sys/vm/drop_caches

linux下有一个posix_fadvise函数可以用来对cache中的文件进行清理,有关posix_fadvise的详细说明查看man手册。

int posix_fadvise(int fd, off_t offset, off_t len, int advice);

”Programs  can  use  posix_fadvise  to  announce an intention to access file data in a specific pattern in the future, thus allowing the kernel to perform appropriate optimisations”

fd是文件的描述符,用于清理对应文件cache的advice值选取POSIX_FADV_DONTNEED,利用此函数编写下面程序进行文件的清理。

int clear_file_cache(const char *filename)
{
	struct stat st;
	if(stat(filename , &st) < 0) {
		fprintf(stderr , "stat localfile failed, path:%s\n",filename);
		return -1;
	}

	int fd = open(filename, O_RDONLY);
	if( fd < 0 ) {
		fprintf(stderr , "open localfile failed, path:%s\n",filename);
		return -1;
	}

	//clear cache by posix_fadvise

	if( posix_fadvise(fd,0,st.st_size,POSIX_FADV_DONTNEED) != 0) {
		printf("Cache FADV_DONTNEED failed, %s\n",strerror(errno));
	}
	else {
		printf("Cache FADV_DONTNEED done\n");
	}

	return 0;
}

此外,linux-ftools这个工具也可以帮助清理并查看文件的内存状态,主页上也有详细的使用说明。编译后我们利用fincore这个工具来查看文件在内存中的状态,有关fincore的实现可以在linux下man mincore,mincore是根据缓存buffer指针来其指向的缓冲区判断在cache中的状态,fincore就是在mincore的基础上直接操作文件,就是通过对文件mmap获得指针,再调用mincore来判断。

首先我们通过cp命令拷贝了一个相对有点容量的文件,然后利用fincore查看文件在内存中的cache情况,可以看到大概cache了99.55%。

image

接着执行上面那段代码的运行程序,之后再执行命令查看该文件的缓存状态

image

可以看到,该文件在内存中已经没有被cache了。实际的清理效果也可以通过一些占用I/O的读文件程序来测试,一般程序第二遍运行时候由于文件已经被cache,实际程序运行的速度会比较快,通过上面的posix_fadivse清理之后,又会恢复和第一遍差不多的时间。

, ,

以下的一段代码是不是很眼熟

     char *a = new char[1024];
     if(a == NULL) {
           //申请失败,处理
     }
     else {
          //正常处理....
     }

的确经常会在程序里这样用,特别是上学时候很多的教科书里想当然的申请失败,返回了NULL。由于使用C++的同学一般不太使用Exception机制,而会忽略异常。其实C++的库中对operator new的声明如下形式。

void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
void* operator new (std::size_t size, void* ptr) throw();

第一种是我们最常使用的,这种方式在申请失败时会抛出std::bad_alloc的异常,而非返回NULL,如下代码。

#include <iostream>
#include <unistd.h>
using namespace std;

int main(void)
{
    while(1) {
        char *a = new char[1024*1024*1024];
        if( a != NULL) {
            cout<<"new 1GB buffer size"<<endl;
        }
        else {
            cout<<"new failed!\n"<<endl;
            return -1;
        }
    }
    return 0;
}

其运行结果如下图,可以看出,程序抛出了std::bad_alloc的异常

第二种则添加了nothrow参数,使得new不抛出异常。
对上面的第8行做如下修改:

        char *a = new(nothrow) char[1024*1024*1024];

从运行结果就可以看出来,程序不抛出异常,而直接返回NULL指针了。

最后一种是placement new,即是在ptr指向的空间上new对象,本身并不申请空间,因此也不会异常。

默认情况下的new是会抛出std::bad_alloc异常的,可以使用set_new_handler来处理默认情况下的异常,代码如下:

#include <iostream>
#include <unistd.h>
using namespace std;

void no_memory () {
  cout << "Failed to allocate memory!"<<endl;
  //这里可以写点清理代码
  throw bad_alloc();  //默认处理函数,继续往上层抛出
  exit (1);
}

int main(void)
{
    set_new_handler(no_momery);
    while(1) {
        char *a = new char[1024*1024*1024];
        if( a != NULL) {
            cout<<"new 1GB buffer size"<<endl;
        }
        else {
            cout<<"new failed!\n"<<endl;
            return -1;
        }
    }
    return 0;
}

则程序执行到new抛出了异常时,会利用set_new_handler的函数进行处理,也可以不throw转而直接exit/return等,执行效果如下:

这段代码告诫自己平常学习应该多钻研,多问,不能想当然,特别是学校课堂上的东西都太过于理想。如果不清楚的应该多看官方一点的东西,有关operator new的东西可以查看这里,描述的很清楚。

强制类型转换

MySQL中提供了两个函数来实现强制类型转换,分别为convert和cast,这两个函数在将一个数值转换为其他类型时的作用几乎一样,写法上略有不同,但convert函数可以将一个值转为其他编码。参考MySQL手册说明:

编码转换:CONVERT(expr  USING transcoding_name),如

image

类型转换:CONVERT(expr , type) 或者 CAST(expr AS type),其中type为以下类型中的一种

  • BINARY [(N)]  转为二进制字符串,后面N为限定长度,有关BINARY类型的参考点这里
  • CHAR [(N)]
  • DATE   日期
  • DATETIME  日期时间
  • DECIMAL [(M[,D])]   转为浮点数,M为数字的长度(包括整数部分和小数部分),N为小数点后位数

转为DECIMAL类似C语言中的atoi函数,即从头扫描字符串直到第一个不为数字的字符截至,对截断的那一位进行四舍五入取整。

默认不限定M,N,转换是转为整数,按照小数点后第一位进行四舍五入。

image

限定M不限定N,则根据数字的位数输出整数,需要注意的是,当M的长度小于实际的数字位数时,会转化成设定为最大的,如下面这个转换,由于设置M为1,即显示不了21这个两位数,就会显示 1位数中最大的9。如果对于设定了小数点后位数N的限定,也会这样转换,同时必须先满足小数点后的N位小数。

image 位数不够显示全部,则

image  满足了1位小数,再取1位整数

image 必须先满足2位小数,不取整数部分。

正常的转换如下,尽可能的将M设置大,而N根据自己的需要选择保留几位小数。

image保留一位小数,第二位四舍五入

image保留两位小数

image保留三位小数,加0补齐位数

需要注意,尽管M可以设置的足够大而不影响数字的长度,但转换依然会先满足小数位数N的需要

image 满足9位小数,只剩1位整数只能取9。

  • SIGNED 有符号整数
  • TIME 日期的时间部分
  • UNSIGNED 无符号整数

image

其中上面的’2’-3由MySQL自动做了一次强制类型转换,根据四则运算将’2’转为了数字2。

自动类型转换

在进行一些四则运算以及逻辑运算时,MySQL也会根据计算的类型以及操作数的类型进行自动转换。

image 四则运算,转为数字操作

image 逻辑运算,转为0或1

image 位操作,转为数字的二进制位。

也可以一些自动进行数字以及字符串向date的转换,例如下面的操作

image

写码过程中碰到这样一个需求。一个table中一列是varchar类型,但是输入的类似是’1.23/张’ 这样的数据,即前面是一个类似单价的东西,后面只是加了一个说明,另外一列为int,需要计算两列的乘积。有了MySQL这样的自动类型转换,就不需要select后逐条的进行atoi的操作,并计算结果进行update了,特别是其中某些列中的数据不全,即varchar为NULL或者int为NULL,会自动不处理,相当的方便哈。如下。

image

最后一句,大爱MySQL哈!!!

, , , ,

搜索引擎利用IR的方法对于一个特定的query检索出该关键词上的出价广告后,就需要对SERP页面上的广告栏分配给出价的广告主,牵扯到搜索广告的排序问题。一般共识是左侧的广告位(即搜索结果页上面的广告位)被看到和点击到的可能性最大,后侧的则按照从高到底排序,越靠上的广告位越好。简单的说就是谁出钱多谁得到的位置越好,复杂的研究这里面牵扯到博弈论之类的问题,假设存在n个对该关键词出价的广告主,k个广告位,每个广告主衡量自己想得到的广告位的价值,并根据他人的出价(有可能是透明,有可能不透明)来决定自己的出价,从而达到自己的宣传效果,同时又想尽可能的减少广告的CPC,而广告竞价又是一个不断变化的过程,如何达到某种相对的均衡状态。

常用竞拍模式

  • First-Price Sealed-bid:一次性竞价,所有人同时出价,出价最高者获得物品,并支付他的出价。
  • Second-Price Sealed-bid:出价方式同上,不同的是实际的支付价格是第二高的竞价。Vickrey拍卖。
  • Open Ascending-bid:最常见的竞价方法,轮流喊,谁喊的最高谁拿,支付他的出价。称为英式拍卖。
  • Open Descending-bid:荷式拍卖,拍卖人从高到低不断的减少定价,第一个能接受价格的人获得物品。

搜索广告的拍卖

Generailized Frist-Price Auction(GFP):第一代拍卖方式,由Overtune.com提出,按照广告主的出价高低对广告进行排名,也引入了CPC机制,使得Overtune.com获得了巨大的成功并成为Yahoo和MSN的SE提供服务。GFP的结果是出价十分不稳定,动态的环境中每个广告主都会不断的调整自己的出价,希望尽可能的降低CPC,获得更高的回报。例如由两个广告位,分别吸引到200个Click和100个Click,之前的出价分别为4$和2$,但可能会不断的调整,调整到2$和2.01$。此时有可能广告主希望获得第一个广告位,出价2.02$,就这样不断的递增,然后递增到一定阈值后,索性放弃,又降到最低的2$,再一次竞价,该过程甚至可以由robot来完成,如下图。

image

Generailized Second-Price Auction(GSP):Google与2002年实现,即每个广告主获得第i个位置实际支付的CPC由第i-1高的支付价决定,可能会略高一点(0.01$),随后Overtune和Yahoo也采用了GSP这种方式,对广告主出价博弈更加友好。GSP的方式一般分为两种

  1. Bid Ranking:按照广告的出价排序,位于第i位的广告的实际CPC为第i+1位的出价,如下图5个广告主在las vagas travel关键词上出价,有4个广告位:               image
  2. Revenue Ranking:按照实际的收益排序,此类排名考虑了每个广告的质量评分,即每个广告的CTR(表示的是广告与query的相关度,广告本身质量等,与位置无关的CTR), 这样可以避免用户看到一些无关的、比较粗糙的广告会对搜索引擎本身产生反感。位置i上的广告主实际支付价格为 bid(i+1)*ctr(i+1)/ctr(i),如果自身广告的质量评分远高于低一位的广告,则可以获得更低的支付价格。image

迄今为止,使用最广告的竞价是GSP,该模型简单有效,也容易向客户进行解释,同时采用广告评分机制,能激励广告商尽可能的优化自己的广告,良好的广告信息对搜索引擎是有益的,对用户是友好的。此外,Vickery-Clark-Groves(VCG)拍卖也会在各个广告拍卖模型中被提起,VCG模型是一次性的对k个物品,n个竞拍者进行拍卖的过程,每一个竞拍者的实际出价由该竞拍者参与后对系统中其他竞拍者带来的损失决定。假设有两个广告位点击率分别为200和100,三个竞价者出价分别为$10,$4,$2。按照VCG模型,获得第二个广告位的人应该支付的价格为$2*100=$200,即因为他的参与,使得出价$2的参与者失去了第二个广告位,系统损失为$200。而第一个广告位获得者的支付价格为$600=$400+$200,$200是由于他的参与使得第三个竞拍者未获得广告位,而$400=$4*100,即他的参与使得出价$4的竞价者失去了以$4的CPC点击100次的广告效应。VCG的计算过程和讲解过程都很复杂,还没找到确切的文档资料说某个搜索引擎完全采用了VCG,有一些猜测G可能换了VCG。

VCG最主要的特性是truth-telling的占优策略,即如何所有的竞价者都真实的评估自己所想要得到的广告位价值,并按照此标准出价。而对于GSP动态中的均衡,Edelman引入了一种Locally envy free equilibrium,是纳什均衡的一种特例,在这种均衡状态下,每一个广告主都无法通过和自己前一位的广告交换出价交换位置得到更高的payoff。(payoff = c(i) * [v(i) – p(i)], c(i)是第i个位置的点击率,v(i)是广告主对第i位的真实估算价值,p(i)是实际的CPC)。

实际上搜索广告的排序除了出价以及广告质量外,还可能受其他各种各样的因素的影响,包括用户的地域、广告主的余额,以及广告主设定的策略等。

参考资料

Internet Advertising and the Generalized Second Price Auction, Edelman

,

搜索引擎的检索结果页下方一般会提示多个相似的搜索关键词,这些词可以被看作查询关键词query的rewriting。在计算广告中,当某一个query没有对应的bid phase出价广告,或者该query对应的bid phase较少的时候,可以利用query rewriting获取相似query对应的广告进行显示,以期望获得更多的click。相似query的确定可以利用用户session中的搜索关键词上下文,但此方法需要确定query的边界,例如用户搜索过程中可能会突然跳到一个完全不相干的搜索,然后又跳回来。或者利用传统的文本相似度匹配,而由于query一般都很短,传统相似度匹配的语料也不足。

image

Simrank

Simrank算法是一种用于衡量结构上下文中个体相似度的方法,直观上的含义是利用已有个体的相似度来推算其他与有关联个体的相似度。形式化的定义如下:

有向图G={V,E}中,节点a的入边集合记为I(a),而出边集合记为O(a),则两个节点a,b(a != b时)相似度s(a,b)按照如下公式计算,其含义是个体a,b的相似度取决于所有与a,b相连节点的相似度,s(a,b)∈[0,1];当a=b时,s(a,b)=1;如果a != b,且只有同一个入节点c,我们不希望从c计算得到的s(a,b)也为1,因此c做为衰减因子,取值是[0,1],即s(a,b) = C。

image

对于二分图G’ = (V1,V2,E),对于任意的(A,a)∈E,有A∈V1和a∈V2,则所有V1集合中的节点相似度按照出度O(A)计算。V2集合中的节点相似度则按照上述公式,利用入度I(a)计算。

image

在搜索广告中,把query和ad看作节点,当用户搜索某个查询关键词q时,点击了广告a,则建立q至a的一条边,这样构成一个由query和ad组成的二分图G=(V,E),其中V=Vq∪Va,任何边e=(q,a,w),q∈Vq并且a∈Va,可以利用simrank算法来求query之间的相似度。E(q)表示q的边,N(q)表示E(q)的个数:

image

按照上述算法,我们看以下的例子,假设C等于0.8,则利用上述公式计算出的sim(pc,camera)的相似度在前5次迭代中都大于sim(camera,digital camera),但从直观上说,由于camera和digital camera的共同邻居较多,应该具备更高的相似度,而simrank的结果是反直观的。针对上述问题,Antonellis等人在VLDB 08上提出了Simrank在计算广告方面的改进——Simrank++。

image

阅读全文…

, ,

简介

计算广告学于2008年由Yahoo Research的A.Broder提出,详细的定义参看百度百科,广义的定义是通过科学计算来选择最优的广告投放,主要研究的是互联网上的广告投放,其中典型的是在搜索引擎上查询关键词结果页出现的“推广链接”。

计算广告(或者说互联网广告)相比于传统的媒体广告的优势在于以下几点:

  1. 投放的介质范围更广。传统的媒体广告一般只有相对较少的场合,例如报纸、杂志、电视、影院、路边广告牌,而互联网上除了大流量网页的banner等,搜索引擎上的一个词语就是一个投放介质。
  2. 广告价格差距。cctv1的广告价格表,稍微像样的时段,30秒的广告都在10万人民币以上,就不提春晚这种露个脸就要上千万的地了。
  3. 个性化。互联网广告可以根据人查询的关键字、Location以及个人信息等进行较为精确的投放。
  4. 衡量投资回报率(ROI)。传统广告很难去衡量这个东西。

目标:

Find the “best match” between a given user in a given context and a suitable adverstiment.

互联网广告常用的付费方式有如下类型

  • CPM(Cost Per Thousand Impressions),按照展示次数付费,主要用于一些图形广告和首页banner。
  • CPC(Cost Per Click),按点击付费,搜索引擎的关键词广告常用付费方式。
  • CPT/CPA(Cost Per Transcation/Action),针对达到成功的营销效果的事务进行付费,例如购物类网站、酒店机票订购,用户消费后像广告投放商进行付费。
  • 此外还有淘宝等国内网站的一种CPT(Cost Per Time),即时间计费,可以包月包日。

计算广告学主要研究的是文本类广告(Textual Ads),文本类广告的投放主要分为两种,由搜索关键词驱动的广告投放和由页面内容决定的广告投放,即Google大名鼎鼎的Adwords和Adsense。当然随着社交网络和SNS的发展,还会出现基于人际关系以及人的特性、行为的”Ad Profile”,例如之前某Boss去米国,一下飞机登录他的Facebook,发现右侧的广告是有关于“英语学习”和”美国回中国机票”。

文本广告组成

一个完整的搜索竞价广告示例,包括出价词语(Bid Phrase)、出价(Bid),标题(Title),描述(Creative),显示的Url(Display URL),而Landing URL是点击该广告的登录页面URL,Landing Page也经常用于关键词广告匹配过程。

image

检索方法概述

广告也可以看作成是一种信息,因此广告的匹配过程可以根据用户输入的查询关键词以及其他一些信息,例如之前搜索的内容、用户的Location等,采用一些传统的IR方法,将广告的出价词语、标题、描述以及Landing Page当做广告文档的语料,用来和用户输入的query进行文档相似度匹配。

A.Broder在SIGIR 2007提出了一种利用web search的结果来对query进行分类、从而进行广告选择的方法。用户在搜索引擎中输入的查询关键词一般都很短,有时候很难通过关键词了解到用户到底需要寻找什么,而通常如果看到了搜索结果的网页,就会了解用户到底要找什么,例如用户搜索一个v880,通过搜索结果页可以了解用户需要找一款Android的手机,此时就可以投放相应的手机广告了,即利用搜索结果为广告的选择提供额外的信息。

image

该方法需要研究的内容就是如何利用搜索结果页,是利用前几项片段还是利用整个结果页,是利用搜索结果页上的快照信息还是利用原网页信息,以及多个搜索结果并不统一,是采用整合还是投票选择机制。

计算广告学其中有很多问题需要算法来进行解决,包括广告分析、Query分析与重写、广告排序(纯粹谁出价高谁排前面就算了)之类的可以学习,本笔记的学习资料来源在这里

, ,