当前位置:天才代写 > tutorial > JAVA 教程 > Java理论与实践:在没有数据库的环境下举办数据库查询

Java理论与实践:在没有数据库的环境下举办数据库查询

2017-11-11 08:00 星期六 所属: JAVA 教程 浏览:311

副标题#e#

我最近仔细考查了一个项目,该项目涉及相当多的 Web 快速搜索。当爬虫程 序爬过差异的 Web 站点时,它将成立一个数据库,该数据库中包罗它所爬过的 站点和网页、每一页所包括的链接、每一页的阐明功效等数据。最终功效是一组 陈诉,具体说明颠末尾哪些站点和页面、哪些是一直链接的、哪些链接已经断开 、哪些页面有错误、计较出的页面规格,等等。开始的时候,没人确切知道需要 什么样的陈诉,可能该当回收什么样的名目 —— 只知道有一些内容要陈诉。这 表白陈诉开拓阶段会是一个重复的阶段,要颠末多次反馈、修改,而且大概实验 利用差异的布局。惟一确定的陈诉要求是,陈诉该当以 XML 形式展示,也大概 以 HTML 形式展示。因此,开拓和修改陈诉的进程必需是轻量级的,因为陈诉要 求是“动态发明”的,而不是预先指定的。

不需要数据库

对这个问题的“最显而易见的”办理要领是将所有对象都放入 SQL 数据库中 —— 页面、链接、怀抱尺度、HTTP 功效代码、计时功效和其他元数据。这个问 题可以借助干系暗示来很好地办理,出格是因为这种要领不需要存储已会见页面 的内容,只需要存储它们的布局和元数据。

到今朝为止,这个项目看起来像是一个典范的数据库应用措施,而且它并不 缺少可供选择的耐久性计策。可是,或者可以制止利用数据库耐久存储数据的复 杂性 —— 这个快速搜索东西(crawler)只会见数万个页面。这个数字不是很 大,因此可以将整个数据库放在内存中,当需要耐久存储数据时,可以通过序列 化来实现它。(是的,加载和生存操纵要耗费较长的时间,可是这些操纵并不经 常执行。)懒惰反而带来了一个长处 —— 不需要处理惩罚耐久性极大地缩短了开拓 应用措施的时间,因而显著地淘汰了开拓事情量。构建和哄骗内存中的数据布局 要比每次添加、提取可能阐明数据时都利用数据库容易得多。不管选择了哪种持 久存储模子,城市限制任何触及到数据的代码的结构。

内存中的数据布局是一种树型布局,如清单 1 所示,它的根是快速搜索过的 各个网站的主页,因此 Visitor 模式是搜索这些主页可能从中提取数据的抱负 模式。(构建一个防备陷入链接轮回 —— A 链接到 B、B 链接到 C、C 链接到 A —— 的根基 Visitor 类并不是很难。)

清单 1. Web 爬行器的一个简化方案

public class Site {
   Page homepage;
   Collection<Page> pages;
   Collection<Link> links;
}
public class Page {
   String url;
   Site site;
   PageMetrics metrics;
}
public class Link {
   Page linkFrom;
   Page linkTo;
   String anchorText;
}

这个快速搜索东西的应用措施中有十多个 Visitor,它们所做的工作雷同于 选择页面做进一步阐明、选择不带链接的页面、列出“被链接最多”的页面,等 等。因为所有这些操纵都很简朴,所以 Visitor 模式(如清单 2 所示)可以工 作得很好,由于数据布局可以放到内存中,因此就算举办彻底搜索,耗费也不是 很大:

清单 2. 用于 Web 快速搜索东西数据库的 Visitor 模式

public interface Visitor {
   public void visitSite(Site site);
   public void visitLink(Link link);
}

噢,健忘陈诉了

假如不运行陈诉的话,Visitor 计策在会见数据方面会做得很是好。利用数 据库举办耐久存储的一个长处是:在生成陈诉时,SQL 的本领就会大放色泽 — — 险些可以让数据库做任何工作。甚至用 SQL 生成陈诉原型也很容易 —— 运 行原型陈诉,假如功效不是所需要的功效,那么可以修改 SQL 查询可能编写新 的查询,然后再试一试。假如改变的只是 SQL 查询的话,那么这个编辑-编译- 运行周期大概很快。假如 SQL 不是存储在措施中,那么您甚至可以跳过这个周 期的编译部门,这样可以快速生成陈诉的原型。确定所需要的陈诉后,将它们构 建到应用措施中就很容易了。

因此,固然对付添加新功效、寻找特定的功效和举办非凡传输来说,内存中 的数据布局都表示得很不错,可是对付陈诉来说,这些酿成了倒霉条件。对付所 有其自身布局与数据库布局差异的陈诉,Visitor 都必需建设一个全新的数据结 构,以包括陈诉数据。因此,每一种陈诉范例都需要有本身的、特定于陈诉的中 间数据布局来存放功效,还需要一个用来填充中间数据布局的会见者,以及用来 将中间数据布局转换成最终陈诉的后处理惩罚(post-processing)代码。好像需要 做许多事情,尤其在大大都原型陈诉将被丢弃时。譬喻,假定您想要列出所有从 其他网站链接到某个给定网站的页面的陈诉、所有外部页面的列表陈诉,以及站 点上链接该页面的那些页面的列表,然后,按照链接的数量对陈诉举办归类,链 接最多的页面显示在最前面。这个打算根基大将数据布局从里到外翻了个个儿。 为了用 Visitor 实现这种数据转换,需要得到从某个给定网站可以达到的外部 页面链接的列表,并按照被链接的页面临它们举办分类,如清单 3 所示:

清单 3. Visitor 列出被链接最多的页面,以及链接到它们的页面

#p#分页标题#e#

public class InvertLinksVisitor {
   public Map<Page, Set<Page>> map = ...;

   public void visitLink(Link link) {
     if (link.linkFrom.site.equals(targetSite)
       && !link.linkTo.site.equals(targetSite)) {
       if (!map.containsKey(link.linkTo))
         map.put(link.linkTo, new HashSet<Page> ());
       map.get(link.linkTo).add(link.linkFrom);
     }
   }
}

清单 3 中的 Visitor 生成一个映射,将每一个外部页面与链接它的一组内 部页面相关联。为了筹备该陈诉,还必需按照关联页面的巨细对这些条目举办分 类,然后建设陈诉。固然没有任何坚苦步调,可是每一个陈诉需要的特定于陈诉 的代码数量却许多,因此快速陈诉原型就成为一个重要的方针(因为没有提出报 告要求),试验新陈诉的开销比抱负环境更高。很多陈诉需要多次通报数据,以 便对数据举办选择、汇总和分类。


#p#副标题#e#

我的数据模子王国

这时,缺少一个正式的数据模子开始成为一项倒霉因素,该数据模子可以用 于描写收集的数据,而且可以用它更容易地暗示选择和聚合查询。也许懒惰不像 开始但愿的那样有效。可是,固然这个应用措施缺少正式数据模子,但也许我们 可以将数据存储到内存中的数据库,并凭借该数据库举办查询,通过这种方法借 用一个数据模子。有两种大概会当即呈此刻您的脑海中:开源的内存中的 SQL 数据库 HSQLDB 和 XQuery。我不需要数据库提供的耐久性,可是我确实需要查 询语言。

HSQLDB 是一个用 Java 语言编写的可嵌入的数据库引擎。它既包括合用于内 存中表的表范例,又包括合用于基于磁盘的表的表范例,设计该引擎为了将表完 全嵌入到应用措施中,消除与大大都真实数据库相关的打点开销。要将数据装载 到 HSQLDB,只需编写一个 Visitor 即可,该 Visitor 将遍历内存中的数据结 构,并为每一个将要存储的实体生成相应的 INSERT 语句。然后可以对这个内存 中的数据库表执行 SQL 查询,以生成陈诉,并在完成这些操纵后丢弃这个“数 据库”。

噢,健忘了干系数据库有多烦人

HSQLDB 要领是一个可行要领,但您很快就发明,我必需为工具干系的不匹配 而两次(而不是一次)受罚 —— 一次是在将树型布局数据库转换为干系数据模 型时,一次是在将平面干系查询功效转换成布局化的 XML 可能 HTML 功效集时 。另外,将 JDBC ResultSet 后处理惩罚为 DOM 暗示形式的 XML 可能 HTML 文档也 不是一项很容易的任务,需要为每一个陈诉提供一些定制的编码。因此固然内存 中的 SQL 数据库 简直 可以简化查询,可是从数据库中存入和取出数据所需要 的特别代码会抵消所有节减的代码。

让 XQuery 来拯救您

另一个容易获得的数据查询要领是 XQuery。XQuery 的利益是,它是为生成 XML 可能 HTML 文档作为查询功效而设计的,因此不需要对查询功效举办后处理惩罚 。这种想法很有吸引力 —— 每个陈诉只有一层编码,而不是两层可能更多层。 因此第一项任务是构建一个暗示整个数据集的 XML 文档。设计一个简朴的 XML 数据模子和编写遍历数据布局,并将每一个元素附加到一个 DOM 文档中的 Visitor 很简朴。(不需要写出这个文档。可以将它保持在内存中,用于查询, 然后在完成查询时扬弃它。当底层数据改变时,可以从头生成它。)之后,所有 要做的就是编写 XQuery 查询,该查询将选择并聚积用于陈诉的数据,并按最终 需要的名目(XML 或 HTML)对它们举办名目化。查询可以存储在单独的文件中 ,以便举办快速原型制造,因此,可支持多种陈诉名目。利用 Saxon 评估查询 的代码如清单 4 中所示:

清单 4. 执行 XQuery 查询并将功效序列化为 XML 或 HTML 文档的代码

#p#分页标题#e#

String query = readFile(queryFile + ".xq");
  Configuration c = new Configuration();
  StaticQueryContext qp = new StaticQueryContext(c);
  XQueryExpression xe = qp.compileQuery(query);
  DynamicQueryContext dqc = new DynamicQueryContext(c);
  dqc.setContextNode(new DocumentWrapper(document, z.getName(), c));
  List result = xe.evaluate(dqc);
  FileOutputStream os = new FileOutputStream(fileName);
  XMLSerializer serializer = new XMLSerializer (os, format);
  serializer.asDOMSerializer();
  for(Iterator i = result.iterator(); i.hasNext(); ) {
    Object o = i.next();
    if (o instanceof Element)
      serializer.serialize((Element) o);
    else if (o instanceof Attr) {
      Element e = document.createElement("scalar");
      e.setTextContent(((Attr) o).getNodeValue());
      serializer.serialize(e);
    }
    else {
      Element e = document.createElement("scalar");
      e.setTextContent(o.toString());
      serializer.serialize(e);
    }
  }
  os.close();

#p#副标题#e#

暗示数据库的 XML 文档的布局与内存中的数据布局稍有差异,每一个 <site> 元素都有嵌套的 <page> 元素,每一个 <page> 元 素都有嵌套的 <link> 元素,而每一个 <link> 元素都有 <link-to> 和 <link-from> 元素。实践证明,这种暗示要领对付 大大都陈诉都很利便。

清单 5 显示了一个示例 XQuery 陈诉,这个陈诉处理惩罚链接的选择、分类和表 示。它有几个处所优于 Visitor 要领 —— 不只代码少(因为查询语言支持选 择、堆积和分类),并且所有陈诉的代码 —— 选择、堆积、分类和暗示 —— 都在一个位置上。

清单 5.生成链接次数最多的页面的完整陈诉的 XQuery 代码

<html>
<head><title>被链接最多的页面 </title></head>
<body>
<ul>
{
  let $links := //link[link-to/@siteUrl ne $targetSite
            and link-from/@siteUrl eq $targetSite]   for $page in distinct-values($links/link-to/@url)
  let $linkingPages := $links[link-to/@url eq $page]/link- from/@url
  order by count($linkingPages)
  return
   <li>Page {$page}, {count($linkingPages)} links
   <ul> {
    for $p in $linkingPages return <li>Linked from {$p/@url}</li>
   }
   </ul></li>
}
</ul> </body> </html>

竣事语

从开拓本钱角度看,XQuery 要领已证实可以节省大量本钱。树型布局对付构 建和搜索数据很抱负,但对付陈诉,就不是很抱负了。XML 要领很适合于陈诉( 因为可以操作 XQuery 的本领),可是对付整个应用措施的实现,该要领尚有很 多未便,并会低落机能。因为数据集的巨细是可打点的 —— 只有几十兆字节, 所以可以将数据从一种名目转换为从开拓的角度看最利便的另一种名目。更大的 数据集,好比不能完全存储到内存中的数据集,会要求整个应用措施都环绕着一 个数据库构建。固然有很多处理惩罚数据耐久性的好东西,可是它们需要的事情都比 简朴哄骗内存中数据布局要多得多。假如数据集的巨细符合,那么就可以同时利 用这两种要领的优点。

 

    关键字:

天才代写-代写联系方式