[CareerCup] 10.7 Simplified Search Engine 简单的搜索引擎

 

10.7 Imagine a web server for a simplified search engine. This system has 100 machines to respond to search queries, which may then call out using processSearch(string query) to another cluster of machines to actually get the result. The machine which responds to a given query is chosen at random, so you can not guarantee that the same machine will always respond to the same request. The method processSearch is very expensive. Design a caching mechanism for the most recent queries. Be sure to explain how you would update the cache when data changes.

 

这道题说假设有一个简单搜索引擎的网络服务器,系统共有100个机子来响应检索,可以用processSearch(string query)来得到其他机子上的结果,每台机子响应检索是随机的,不保证每个机子都会响应到同一个请求。processSearch方法非常昂贵,设计一个缓存机制来应对近期检索。根据书中描述,我们先来做一些假设:

1. 与其说根据需要调用processSearch,倒不如设定所有的检索处理发生在第一个被调用的机子上。

2. 我们需要缓存的检索是非常大量的。

3. 机器之间的调用很快。

4. 检索的结果是一个有序的URL链表,每个URL由50个字符的标题和200个字符的概要组成。

5. 最常访问的检索会一直出现的缓存器中。

 

系统需求:

主要需要实现下列两个功能:

1. 高效查找当给定了一个关键字时

2. 新数据会代替旧数据的位置

我们还需要更新和清楚缓存当搜索结果改变了。由于一些检索非常的常见病永久的在缓存器中,我们不能等缓存器自然失效。

 

步骤一:设计单个系统的存存器

我们可以混合使用链表和哈希表来实现,我们建立一个链表,当某个节点被访问了,自动将其移到开头,这样链表的末尾就是最老的数据。我们用哈希表来建立检索和链表中节点的映射,这样不仅可以让我们高效的返回缓存的结果,而且可以把节点移到链表前段,参见代码如下:

 

class Node {
public:
    Node *pre;
    Node *next;
    vector<string> results;
    string query;
    Node(string q, vector<string> res) {
        results = res;
        query = q;
    }
};

class Cache {
public:
    const static int MAX_SIZE = 10;
    Node *head, *tail;
    unordered_map<string, Node*> m;
    int size = 0;
    Cache() {}
    void moveToFront(Node *node) {
        if (node == head) return;
        removeFromLinkedList(node);
        node->next = head;
        if (head != nullptr) {
            head->pre = node;
        }
        head = node;
        ++size;
        if (tail == nullptr) {
            tail = node;
        }
    }
    void moveToFront(string query) {
        if (m.find(query) == m.end()) return;
        moveToFront(m[query]);
    }
    void removeFromLinkedList(Node *node) {
        if (node == nullptr) return;
        if (node->next != nullptr || node->pre != nullptr) {
            --size;
        }
        Node *pre = node->pre;
        if (pre != nullptr) {
            pre->next = node->next;
        }
        Node *next = node->next;
        if (next != nullptr) {
            next->pre = pre;
        }
        if (node == head) {
            head = next;
        }
        if (node == tail) {
            tail = pre;
        }
        node->next = nullptr;
        node->pre = nullptr;
    }
    vector<string> getResults(string query) {
        if (m.find(query) == m.end()) return vector<string>();
        Node *node = m[query];
        moveToFront(node);
        return node->results;
    }
    void insertResults(string query, vector<string> results) {
        if (m.find(query) != m.end()) {
            Node *node = m[query];
            node->results = results;
            moveToFront(node);
            return;
        }
        Node *node = new Node(query, results);
        moveToFront(node);
        m[query] = node;
        if (size > MAX_SIZE) {
            for (unordered_map<string, Node*>::iterator it = m.begin(); it != m.end(); ++it) {
                if (it->first == tail->query) m.erase(it);
            }
            removeFromLinkedList(tail);
        }
    }
};

 

步骤二: 扩展到多个机子

对于多个机子,我们有许多中选择:

选择1:每个机子有自己的缓存器,这种方法的好处是快速,因为没有机子间的调用,但是缺点是不高效

选择2:每个机子都有缓存器的拷贝,当新项目添加到缓存器,发送给所有的机器,设计目的是为了让常用检索存在于所有机子上,缺点是缓存器的空间有限,无法保存大量数据

选择3:每个机器保存缓存器的一部分,当机器i需要得到一个检索的结果,它需要找出哪个机子有这个结果,并到那个机子上取结果。但是问题是机子i怎么知道那个机子上有结果,我们可以用哈希表来建立映射,hash(query)%N,能快速知道哪个机子有想要的结果。

 

步骤三:更新结果当内容改变

有些检索很常用,所以会永远存在缓存器中,我们需要一些机制能更新结果,当其内容改变了,缓存器中的结果页应该相应变换,主要有下列三种情况:

1. URL的内容改变了

2. 当网页的排行改变了,那么结果的顺序也变了

3. 对于特定的检索有了新的页面

对于1和2,我们建立单独的哈希表告诉我们哪一个检索和哪个URL之间有映射,这个可以在不同的机子上分别完成,但是可能会需要很多数据。另外,如果数据不需要即时刷新,我们也可以周期性的来更新缓存器。对于3,我们可以实现一个自动超时机制,我们设定一个时间段,如果在这个时间段里没有检索,不管它之间被检索的有多频繁,我们都清除它,这样保证了所有数据都会被周期性的更新。

 

步骤四:进一步地增强

一个优化是当某个检索特别频繁时,比如一个检索占了1%的比重时,我们与其让机器i发送请求给机器j,倒不如在机器i上将结果存在自己的缓存器中。

再有就是我们将检索根据哈希值分别不同机器,而不是随机分配。

另外一个优化就是之前提到的自动超时Automatic Time Out机制,就是x分钟后自动清除数据,但是有时候我们对不同的数据希望设定不同的x值,这样每一个URL都有一个超时值基于此页面过去被更新的频率。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于信息检索系统——“Baioogle-SearchEngine(百歌搜索引擎)”的说明: (注:本程序的tomcat集成版即精简了配置操作,另见下载地址 http://download.csdn.net/source/3332605) =============================================================================== 一、系统简介: 1.本系统为B/S结构的web应用系统,是基于Apache lucene(全文检索功能)以及ajax(GoogleSuggest功能)等技术开发的全文信息检索系统,目前仅支持对纯文本文件的检索 2.系统名称:Baioogle-SearchEngine,即“百(度谷)歌”搜索引擎 3.开发人:ZHG工作室 2008.5 (E-mail:wudazhg@163.com) 4.其src文件夹内为全部源代码,WebRoot为web应用部署文件 5.本系统的最小有效组件集合为:(约定:以下“*.*”均表示目录下的所有单独文件,不包括文件夹,而“/s”则表示所有的文件夹及其内部内容) src\*.* /s WebRoot\WEB-INF\classes\terms.mdb WebRoot\WEB-INF\classes\dict\*.* /s WebRoot\WEB-INF\classes\org\mira\*.class /s WebRoot\WEB-INF\lib\lucene-core-2.3.1.jar WebRoot\*.* WebRoot\WEB-INF\index WebRoot\WEB-INF\*.* WebRoot\cache\wget.exe WebRoot\cache\make-cache.bat 6.本系统最终运行组件包(发行包)仅包括WebRoot内的文件。src内的文件为本系统的源代码,但src的内容要正常编译仍离不开WebRoot内的部分文件 二、注意事项: 1.关于以上所列出的最小有效组件集,对于非熟悉本系统开发原理者不应再进行缩减,否则可能不能顺利运行本程序 2.本系统依赖于网络爬虫软件wget的自动存放格式,如网址“http://127.0.0.1:8080”所对应的目录形式将为“http\127.0.0.1+8080”。但目前仅能处理省略端口的形式的网址(即端口为80时),未考虑其他端口时的情况(此局限之处有待完善) 3.如果要对站内文件进行索引,在运行建立索引命令时,最好将相应.bat命令文件的路径参数改为绝对路径 4.由于参考了部分开源技术,故在开发过程尽量保留原作者信息,如在版权等问题上有处理不当之处,纯属学习借鉴,无侵权之意,望见谅 5.本系统开源,在传播过程请保持整个软件包的完整性。本软件仅供学习参考之用,所有权保留 三、使用步骤: 1.编译src的*.java文件。(src的个目录下有compile.bat文件,可简化编译过程。由于现在(2008.5-zhg)发行时已经用jdk1.5+tomcat5.5编译过,故可跳过这步。如运行提示版本错误,也可重新编译) 2.运行WebRoot\cache\make-cache.bat命令,来抓取网络资源,建立快照。 3.运行WebRoot\WEB-INF\IndexHTML-by-Cache.bat命令,来为快照网页建立索引。 4.运行WebRoot\WEB-INF\make-db.bat命令,从索引库读取关键字信息自动存入WebRoot\WEB-INF\classes\terms.mdb,以便GoogleSuggest功能使用 5.将WebRoot目录部署到web服务器(tomcat)。(上下文路径可自定,建议定为“/baioogle”) 6.打开web浏览器输入相应地址(如“http://127.0.0.1:8080/baioogle”)即可进入本系统主界面 四、作者信息 ----------------------------------------------- -----------------Copyright©-------------------- ----------------------------------------------- ------ Author:ZHG工作室 2008.5 ------- ------ E-mail:wudazhg@163.com ------- ------ All Rights Reserved ------- ----------------------------------------------- ----------------------------------------------- ----------------------------------------------- ===================================================================================== ---Author:zhg 2008.5

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值