Category: 编程、软件、技术

  • SOLR之初体验——第一部分

    我准备用两部分来讲述SOLR的体验。第一部分,牵涉到后端,主要是SOLR的安装、启动、数据库配置;第二部分,牵涉到前端,主要是用Solarium提供的PHP接口在PHP中进行操作。

    本篇是第一部分。

    SOLR由Apache发行,是一个源自Apache Lucene的开源、企业级、搜索引擎项目。 在Sitepoint.com的这一系列文章详细讲述了SOLR和Solarium,有兴趣的读者可以自行浏览。

    安装、启动SOLR当前版本为4.8.0,以压缩包方式发布,有发行版现成使用和源代码供自行编译。下载地址:https://lucene.apache.org/solr/downloads.html

    SOLR发行包不大,压缩后仅150M左右。解压到某个目录后,安装就可以认为已经完成——当然还需要正确版本的Java支持,SOLR对Java的要求是在1.7以上。我的安装目录在:

    ~/temp/solr-4.8.0

    SOLR的发行版有一个内置的样本服务器配置,在example目录下,而其中又有一个样本数据库solr。 首先让我们启动这个数据库,看看有些什么东西。

    tr@hp:~/temp/solr-4.8.0/example$ java -jar start.jar

    这样就启动了SOLR服务,该服务缺省开放了8983端口的WEB管理界面,我们可以远程访问之:

    Ashampoo_Snap_2014.05.03_10h30m21s_011_Solr

    出现这个界面后,我们可以放心了:SOLR服务已经正常启动。SOLR确实是非常吃内存的服务,2G的内存空间被吃掉了1.75G。看来,要充分跑起SOLR,4G是最低配置了。

    在左侧“Core Selector”下拉框中选择一个我们要管理的核心——目前也只有一个,名叫“collection1”,于是就进入该核心的管理页面。在我看来,一个核心或者说这里的collection1,就相当于一张表格,用来保存我们需要进行索引和搜索的数据。此时界面变为对该核的管理界面:

    Ashampoo_Snap_2014.05.03_10h30m03s_010_SolrAdminMozillaFirefox_thumb.png

    左侧边栏有不少新的可选命令。我们会慢慢看。

    配置Schema和中文支持在上图中,可以看到SOLR这个实例的运行环境。对该实例,我们需要定制它的schema。SOLR使用XML文件来配置表格的结构,该文件名为schema.xml,位于example/solr/collection1/conf目录下。SOLR似乎只依赖这单一一个文件进行数据库的管理。每次SOLR启动的时候会对该文件进行扫描并进行后台的重建(比如增加/删除了字段,改变了字段的类型和属性等),但是并不会丢失数据 SOLR样本数据库中的schema.xml非常庞大,作为用户,有必要进行定制。

    另外一个对于全文搜索引擎而言,至关重要的是其对非英文内容的处理,对我来说,就是对中文的处理。所幸的是,SOLR对中文内容处理的非常好。

    schema.xml基本结构如下:

    • 首行,必然是标准的XML文件声明:<?xml version=1.0 encoding=UTF-8 ?>
    • 跳过很长的注释后,就进入schema声明:<schema name=resource version=1.5>name用来标记这个schema,而version是该schema定义时用到的语法的版本,目前就用1.5好了。
    • 字段定义。SOLR有几个保留的字段名,分别是_version_(用于schema的版本更新维护),_root_(在使用嵌套文档的时候要用),id(唯一标识符,建议保留)。
    • 字段定义由若干XML属性完成,常见的有:
      • name:字段名
      • type:字段类型
      • indexed:是否要加入索引
      • stored:是否存入数据库
      • required:是否必须
      • multiValued:是否允许有多个该字段的值。比如一个文档的tag通常是多个,因此这个字段的定义我一般会设置multiValued=true
    • 字段类型的元定义。这个用来定义上面定义的字段的类型。比如一个int是怎样的类型?这点很奇怪,因为在我看来,这些基本类型应该不用再定义的。但是既然SOLR有这个要求,我们也不妨遵循。
    • 这个元定义中需要特别提一提text_cjk这个类型。它就是对一个中文字段进行全文分词检索的关键。如果一个字段是中文内容,并且我们要对它进行全文检索,那么将这个字段设置为这个类型比较好。
  • 任氏有无轩最新改版

    任氏有无轩改版已经很多次了,从最早的Symfony 1.x开始,在Symfony框架进入到2.x的时候重新改版了一次,最近的这次刚刚结束,也算是很大的一次。

    根据我在Bitbucket的提交记录,3月12日开始第一次重新提交,4月22日完成最后一次的提交,历时40余天。但是,众所周知,我的开发是很断续的,平均下来每天投入的时间不会超过1个小时,所以这次改版的总耗时不超过40小时,也就是常规工作时间下一周的工作量——加班的话也就3天左右。

    这次的改版牵涉面非常广。

    前端我还是使用Symfony 2来搭建我的应用,这个框架我已经用了很多年,如果没有什么大的变动和根本性的原因,我应该不会轻易切换别的框架——比如这个帖子里提到的Laraval和Phalcon。

    我原来的站点是用Bootstrap自己搭建的。优点是没有约束,自由度大,而且Bootstrap提供的部件已经给出了足够的基础来进行这个工作;缺点是我不是设计人员,设计出来的页面总是脱不了Bootstrap本身提供的一些模板。所以,下定决心花了$4在wrapbootstrap.com买了一个商业模板Grove(顺大便说一句,这个模板涨到$12了)。

    用商业模板的好处是,总可以找到适用的基本页面来改造;缺点是,很依赖它提供的样式。不过总的来说,利大于弊,我觉得我这个$4花得很值得。 另外,也许是我运气好,这个模板还提供了一个3D/2D幻灯片过渡的库,让我轻松做出很炫的Carousel场景切换效果。

    最后,我还加入了长久以来一直缺失的按照书籍tag搜索书籍的功能。下一步,我还想加入一个tag云。

    后端**后端是这次改动最大的地方。**

    首先,数据库结构重新编写。

    在我给Sitepoint写的文章中,我明确表示:我是很反对使用一个自增长的整数字段来作为主键(Primary Key)的。但是,为了进行Symfony 2下的数据自动填充和另外一个后台(还没有实现)Phreeze的要求,我不得不重新构造我的数据库为那些原来没有自增长字段PK的表格重新加入这样的一个主键。数据迁移工作也花费了不少重复性的工作。

    第二,部分前端的动态内容提供,我开始采用Dart,而不是之前的纯jQuery。使用Dart,我的开发速度大大加快。虽然有一些限制——比如我这个帖子中提到的,但是总体来说利大于弊,而且我作为曾经在苏州Google Developer Group组织的Fly Dart活动中主讲过Dart的人,当然那更应该以身作则,多使用一些Dart。

    第三,我整合了Wordpress的一些功能,比如获得最新的N个帖子。

    总的来说,这次的改造是非常成功的,部署也很顺利。感觉自己对Symfony 2的掌握又深入了一层。 放张首页的效果图(点击可看大图):

    Ashampoo_Snap_2014.04.23_19h33m20s_001_Chrome

  • 在Symfony 2中获取WordPress信息

    在我正在进行的任氏有无轩改版中,我希望在首页获得我的博客的一些信息,比如最新发布的五个帖子。

    我使用的博客后台是Wordpress,它提供了很好的编程接口,可以轻松地完成这个任务。而且Wordpress也提供了这些编程接口的说明。

    Wordpress对博客信息的操作是通过所谓的XML-RPC实现的,其官方文档见此处。它也提供了诸如MetaWeblog API接口和其它格式的API接口。经过比较后,我还是选择使用MetaWeblog API接口,主要是因为它调用相对更加简单,返回值虽然不完整,但是够用也很精练。

    获取最新的若干(缺省为4)篇帖子的代码如下:

    private function getRecentPostsFromWP($num=4)
        {
            require_once 'wordpress/wp-includes/class-IXR.php';
            $user='user';
            $pwd='password';
            $xmlclient='http://www.rsywx.net/wordpress/xmlrpc.php';
            $client=new IXR_Client($xmlclient);
            $params=array(0, $user, $pwd, $num);
            $client->query('metaWeblog.getRecentPosts', $params);
            $posts=$client->getResponse();
            return $posts;
        }

    这个函数以数组形式返回最新的几个帖子,在Twig中可以进一步使用诸如:

    {{rp.title}}
    {{rp.dateCreated.year}}年{{rp.dateCreated.month}}月{{rp.dateCreated.day}}日
    {{rp.description|striptags|truncate(120)}}

    等方式获取相关信息并展示。

    有兴趣的读者可以进一步参阅API说明,挖掘Wordpress更多的功能,并应用到自己的站点中。

  • Symfony 2中Twig模板的两个小技巧

    今天抓紧时间又更新了一下任氏有无轩的首页的改造。在我已经获得了我的博客的若干最新帖子的前提下,我需要在首页上显示其中的几个。 我要解决两个问题:

    1. 对帖子的内容进行过滤。
    2. 对过于长的帖子内容进行截断。

    由于Twig引擎在渲染HTML的内容时,缺省会将其作为<pre>文本输出,因此所有HTML/CSS效果都会丢失。这是可以接受的,但是问题在于,在这一过程中所有的HTML标记(如<p><img>等)也会按照转义输出,这样一来我们的输出中文字就会非常凌乱,不利于阅读。

    我要达到的是下面的效果:

    Ashampoo_Snap_2014.04.13_12h33m30s_002_MozillaFirefox.png

    也就是说,只输出文本,对于其中可能出现的HTML标记被剥离并不是太大的问题。 这可以通过如下的输出控制实现:

    rp.description|striptags

    接下来,要对这样输出的文字进行截断。Twig提供了一个truncate过滤器,但是要使用它需要进行一些设置。 修改app/config.yml并增加如下代码:

    services:
        twig.extension.text:
            class: Twig_Extensions_Extension_Text
            tags:
                - { name: twig.extension}

    然后对刚才输出的文字继续套用truncate

    rp.description|striptags|truncate(120)

    就可以得到图片中的效果了。

    本文收录于[go4pro.org]

  • PHP-CPP编写PHP扩展

    (原文发布于2014年3月26日和4月5日,原文链接Getting Started with PHP Extension Development via PHP-CPP,以及PHP Extension Development with PHP-CPP: Object Oriented Code

    本文收录于[go4pro.org]

    这两篇文章利用http://php-cpp.com/提供的PHP-CPP作为基础,讨论了利用C++(严格说是PHP-CPP)编写PHP扩展的方法,讨论了最基础的东西以及一个类(复数类)的基本实现。

  • Symfony 2中的功能测试

    (原文发布于2014年3月4日,原文链接Functional Testing in Symfony 2

    本文收录于[go4pro.org]

    =====

    基于《Symfony 2中的批量数据生成》,我们可以对页面进行有控制的功能测试。所谓“有控制”,意为在测试数据是受控产生的前提下,假定程序逻辑没有问题,那么结果应该是如我们所预期的那样受控。否则程序一定有问题。

  • Symfony 2中的批量数据生成

    (原文发布于2014年2月24日,原文链接:Data Fixtures in Symfony 2

    本文收录于[go4pro.org]

    =======

    本文介绍了在Symfony 2中使用Data Fixtures工具进行批量数据生成的方法。特别介绍了牵涉到1-M等主从表之间PK关联的数据的生成方法。

  • MySQL存储过程中Cursor的使用

    (原文发布于2014年2月5日,原文链接Cursors in MySQL Stored Procedures

    本文收录于[go4pro.org]

    ====

    这篇文章继续了我之前《存储过程》的讨论,专注在讨论Cursor(光标)。这篇的讨论也很热烈。

  • 大整数和任意精度实数运算

    (原文发布于2014年1月29日,原文链接Arbitrary Precision and Big Numbers in PHP

    本文收录于[go4pro.org]

    ====

    严格的说,这是一篇纯算法的文章,文中讨论了三个PHP库:BC,GMP,php-bignumber,并分别用计算圆周率和进行RSA加密/解密进行了演示。

  • Symfony和Dart的整合——第二部分

    (原文发布于2014年1月20日,原文链接Integrating Polymer/Dart and Symfony – Part 2

    本文收录于[go4pro.org]

    ====

    在第二部分,我继续讨论Symfony和Dart的整合,还是异步数据的获得——但注重在远程数据,并讨论了一种避免JSONP的方法。同时,对编译为JavaScript后的Dart的局限性进行了讨论。