育炜's profile有为PhotosBlogLists Tools Help

Blog


    March 06

    关于产品设计

    互联网产品的特点

    互联网产品和软件产品不同,相比来说,互联网产品需要更快的开发速度,更灵活的结构,更好的拓展性,更快的更新速度。互联网产品,往往不仅限于功能的实现。而一个成功的产品,除了和用户的交互,功能的强大,便捷,容错能力强之外,文化和氛围的形成,建立,也会对产品起到异常重要的作用。而在产品规模到达一个层面的时候,通常需要对平台本身结构,功能,技术,体验等方面的突破,以至达到概念的突破,才能让产品再次迸发出生命力和竞争力。

    什么时候需要产品设计

    任何时候产品都需要不断的更迭和完善。但是基于互联网产品的特点,在产品新推出,和平台到达一个规模瓶颈的时候,尤其需要通过设计来提高产品的竞争力,从而迅速占领市场。产品前期的结构是否合理和灵活,也决定了产品后期的改造,平台整合,功能和资源输出是否能快速小代价的执行。

    什么人应该懂得产品设计

    产品设计人员(产品的功能设计人员)无疑需要精通产品设计。其实,一个产品生产团队的所有人,都应该或多或少懂得产品设计,至少有产品设计的理念。一个再好的功能设计师,也没办法把所有执行层面的产品细节设计到位。而且也没有充足的时间让大家这么作。那么遇到产品执行细节的时候,必定需要各执行层的人员在专业技能之外,用产品的理念进行执行。

    例子:

    比如yahoo美国首页的更多服务菜单,这个菜单通过一次点击从左边移出。产品人员可以设计这个菜单的通过什么动作激活出现,从什么地方出现,什么时候消失,但是没办法设计这个菜单移出的速度。是匀速移出,加速移出还是减速移出。移出到制定位置的时候是否要做急停或者抖动效果。

    上述的这些是需要动画设计师和工程师合作来完成的,不仅仅是产品人员。

    产品人员在设计流程的时候,也可能不甚了解某个新特效或者交互形式的应用,会对现有的开发有多大程度的影响。这时候,产品人员需要和相关的技术工程师沟通来确定具体的流程或者交互逻辑应该如何设计。

    因此好的产品人员不一定在各个执行层面都是强手,但是好的产品人员一定要懂得如何和专业人员沟通,从而可行的好的产品方案。

    产品设计都设计什么

    产品设计绝不是单纯对功能的增减。往往出现的一个现象,是产品人员拿着功能列表的单子,和大家讨论哪些功能要,哪些不要,哪些一期做,哪些二期做。在时机不恰当的时候,就陷入了细节的泥潭,而忘记整体的目标。最后的产品就成了一个功能堆砌的场所,而很难表现出原本的主张。之前说过,很多的细节是需要和专业的执行人员协调沟通来执行的。产品人员一定要在整个过程中,可以看到大的产品目标和方向,不能让自己迷失。这个时候一定不能忘记目标用户群、平台优势、定位、资源。

    关于用户心理模型和产品设计模型

    产品的设计模型,其实我更愿意说产品实现模型。往往设计模型和实现模型是有差距的。而用户也往往没有按照我们预先设计的模型来使用产品。一个产品模型为用户提供了很多可能。产品人员也要通过最终用户的使用情况来判断产品的实现模型是否和用户的心理模型匹配。

    用户使用产品的时候通常现如下:

    需求目标->分解成若干任务->按照产品规则进行交互->对照心理预期验证执行结果

    这个路径通常不是唯一的,也可能在交互的过程中,用户的早期需求目标就发生了改变。因此,条条大路通罗马。关键是不要总让用户在最后失望。

    产品设计的依据

    如何判断产品设计是否合格,是否达到了目标。产品的数据指标是足够客观的。但是也往往难以直接揭示问题。而且往往在产品发布之前,产品人员就需要取得足够的依据以便可以在验证团队的想法。

    通常评审产品的方法有“焦点小组”和“用户可用性测试”。焦点小组的评审方式更崇尚经验和专业。而互联网产品的用户群体和文化往往变化较快,所以焦点小组的评审略显主观和狭窄。目前业界更为推崇“用户可用性测试”。

    在可执行层面来说,部分主要功能的可用性测试,整体使用流程的可用性测试,还有在线调查的方式都可以在设计前期取得相当的数据依据。在产品上线后再辅以数据分析,进行产品的调整。

    如何理解“我们”设计的平台

    产品人员是否真的“懂”我们要设计的平台。对一个有交互氛围的产品平台进行设计把握,一定要真的懂得用户是如何使用类似的平台,用户如何使用我们的平台。这需要产品人员能充分的体验用户使用这些平台的感受,更要能预测出用户即将产生的需求。产品人员一定要大量的使用这些平台,要让自己先成为一个足够深度的“玩家”。

    Colors Reference [Transshipment]

    source url:http://www.smashingmagazine.com/category/color

     

    Sometimes we just don’t know what color to use. Sometimes we have no idea which colors to combine in order to create a beautiful color palette which would attract the visitors of our web-sites. That’s why we’ve decided to create some kind of visual reference cards or cheat sheets for the most popular colors of Web 2.0. Green, Purple, Black, White and other colors will be reviewed and analyzed in the next articles.

    Today’s Color is green. You can download it from our web-site. Please don’t refer to the image in your blog posts, but to this article. We’ve invested a lot of time creating it. So if you’d like to use it, at least appreciate our work. Please.


     

     

     

     

    July 25

    再见了Embed,一些媒体播放器的符合web标准的代码[转]

    再见了Embed,一些媒体播放器的符合web标准的代码

     

    由于Embed标签是Netscape的私有财产,故一直未被W3C认可,对于各种媒体文件使用Embed标签是非标准的,如何改变?Elizabeth

    Castro Bye Bye Embed

    一文对于各种媒体播放器给出了很好的符合web标准的代码。

     

    在线媒体播放--Google Video and YouTube

     

    <object type="application/x-shockwave-flash"

      data="http://video.google.com/googleplayer.swf? » 8755581808731033658"

      width="400" height="326" id="VideoPlayback">

      <param name="movie"

        value="http://video.google.com/googleplayer.swf? » docId=8755581808731033658" />

      <param name="allowScriptAcess" value="sameDomain" />

      <param name="quality" value="best" />

      <param name="bgcolor" value="#FFFFFF" />

      <param name="scale" value="noScale" />

      <param name="salign" value="TL" />

      <param name="FlashVars" value="playerMode=embedded" /> </object>

    其实就是FLASH文件的调用

     

    Windows Media Player 文件

     

    <object type="video/x-ms-wmv"

      data="http://www.sarahsnotecards.com/catalunyalive/ » fishstore.wmv"

      width="320" height="260">

      <param name="src"

        value="http://www.sarahsnotecards.com/catalunyalive/ » fishstore.wmv" />

      <param name="autostart" value="true" />

      <param name="controller" value="true" /> </object>

    上面的代码没有Windows Media

    Player特有的classid,作者在IE5.5, IE6, IE7, Opera Win/Mac, Firefox Win/Mac, Safari下测试通过。

     

    QuickTime movies 没有 embed 标签

     

     

    <object classid="clsid:02BF25D5-8C17-4B23-BC80- » D3488ABDDC6B"

      codebase="http://www.apple.com/qtactivex/qtplugin.cab"

      width="320" height="260">

      <param name="src"

        value="http://www.sarahsnotecards.com/catalunyalive/ » diables.mov" />

      <param name="controller" value="true" />

      <param name="autoplay" value="false" />

      <!--[if !IE]>-->

      <object type="video/quicktime"

        data="http://www.sarahsnotecards.com/catalunyalive/ » diables.mov"

        width="320" height="260">

        <param name="autoplay" value="false" />

        <param name="controller" value="true" />

      </object>

      <!--<![endif]-->

    </object>

    出处:蓝色理想

     

    --~--~---------~--~----~------------~-------~--~----~

    You received this message because you are subscribed to the Google Groups "web

    技术研究与应用" group.

    To post to this group, send email to webbase@googlegroups.com To unsubscribe from this group, send email to webbase-unsubscribe@googlegroups.com

    For more options, visit this group at http://groups.google.com/group/webbase

    -~----------~----~----~----~------~----~------~--~---

     

    July 21

    用ASP.NET上传图片并生成带版权信息的缩略图

    <%@ Page Language="C#" ResponseEncoding="gb2312" %>
    <%@ import Namespace="System" %>
    <%@ import Namespace="System.IO" %>
    <%@ import Namespace="System.Drawing" %>
    <%@ import Namespace="System.Drawing.Imaging" %>
    <script runat="server">

    void Page_Load(Object sender, EventArgs e)
    {
    if(!Page.IsPostBack)
    {
    ImgPreview.Visible=false;
    }
    }
    void GetThumbnailImage(int width,int height,string strInfo,int left,int right)
    {
    string file="Uploads/"+uploadFile.PostedFile.FileName.Substring(uploadFile.PostedFile.FileName.LastIndexOf('\\')+1);
    string newfile="Uploads/"+uploadFile.PostedFile.FileName.Substring(uploadFile.PostedFile.FileName.LastIndexOf('\\')+1)+".jpg";
    string strAdd=strInfo;
    System.Drawing.Image oldimage = System.Drawing.Image.FromFile(Server.MapPath(file));
    System.Drawing.Image thumbnailImage =
    oldimage.GetThumbnailImage(width, height,new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
    Response.Clear();
    Bitmap output=new Bitmap(thumbnailImage);
    Graphics g=Graphics.FromImage(output);
    g.DrawString(strAdd,new Font("Courier New", 14),new SolidBrush(Color.Red),left,right);
    output.Save(Server.MapPath(newfile),System.Drawing.Imaging.ImageFormat.Jpeg);
    Response.ContentType = "image/gif";
    ImgPreview.Visible=true;
    ImgPreview.ImageUrl=newfile;
    }
    bool ThumbnailCallback()
    {
    return true;
    }

    void Button_Click(object sender, EventArgs e)
    {
    int width,height,left,right;
    string strAddInfo=txtAddInfo.Text;
    width=Int32.Parse(txtWidth.Text);
    height=Int32.Parse(txtHeight.Text);
    left=Int32.Parse(txtLeft.Text);
    right=Int32.Parse(txtRight.Text);
    if(!(uploadFile.PostedFile.ContentLength>0))
    {
    lblErrInfo.Text="没有选择文件";
    }
    else
    {

    string path = Server.MapPath("./Uploads/"+uploadFile.PostedFile.FileName.Substring(uploadFile.PostedFile.FileName.LastIndexOf('\\')+1));
    if(File.Exists(path))
    {
    lblErrInfo.Text="已经有同名文件";
    }
    else
    {
    uploadFile.PostedFile.SaveAs(path);
    GetThumbnailImage(width,height,strAddInfo,left,right);
    }
    }
    }
    </script>
    <html>
    <head>
    </head>
    <body>
    <form method="post" enctype="multipart/form-data" runat="server">
    <p>
    <input id="uploadFile" type="file" runat="server" />
    <asp:Label id="lblErrInfo" runat="server" forecolor="Red"></asp:Label>
    </p>
    <p>
    width:<asp:TextBox id="txtWidth" runat="server" Width="40px">100</asp:TextBox>
    height:<asp:TextBox id="txtHeight" runat="server" Width="40px">150</asp:TextBox>

    </p>
    <p>
    添加信息:<asp:TextBox id="txtAddInfo" runat="server">AspxBoy.Com</asp:TextBox>
    </p>
    <p>
    信息位置:left:<asp:TextBox id="txtLeft" runat="server" Width="40px">10</asp:TextBox>
    right:<asp:TextBox id="txtRight" runat="server" Width="40px">135</asp:TextBox>
    </p>
    <p>

    <input id="button" type="button" value="上传生成缩略图" onServerClick="Button_Click" runat="server" />
    </p>
    <p><asp:Image id="ImgPreview" runat="server"></asp:Image>
    </p>
    <!-- Insert content here -->
    </form>
    </body>
    </html>
    July 18

    MSN无法登陆(登录)的解决方法[转]

     
    不知道怎么回事,最近一段时间MSN登陆非常困难,必须尝试多次才有可能成功。一个偶然的机会,发现下面的方法可以快速登陆。

    MSN无法登录的几种可能原因和解决方法:

    1、最有可能的原因: 系统时间错误

    返回信息:80048820,总是说防火墙设置阻止MSN的连接。但在MSN的网络连接测试中都是成功。

    解决方法:系统日期不对造成的!!!!,请你认真查看是否在你升级到MSN7.5以后,系统日期变成了2004年,如果是直接将系统日期改成现在的时间。

    点击右下角系统时间设置为当前正确时间。OK!

     

    2、原因不明:系统为MSN 7.5

    解决方法:打开“Internet Explorer”,点击“工具”里的“Internet选项”,选“高级”,点击“还原默认设置”,再点击“应用”,最后“确定”,一切搞定,就这么简单

    3、原因不明:

    解决方法:当登陆MSN返回“重试”,“取消”和“帮助”三个选项时,先选择“帮助”,再选择“重试”,这样很快就登陆成功了。

    这种方法是某网友WINDOWS 2000,ADSL上网,安装了FW。


    4、80048820 错误

    故障现象:80048820 错误,用MSN连接检测一下说端口有问题,检查时间是正确的

    解决方法:把INTERNET 选项里的 检查服务器证书吊销状态的勾去掉就可以了。

    谢谢,我的也是报的这样的错,用这个方法成功了

    5、由于病毒防火墙引起

    解决方法:如果用的是norton病毒防火墙,在Norton个人防火墙设置中,将程序列表中有MSN MESSAGE程序,左击中间下拉菜单,将其改为全部允许.

     
    6、封包长度不对

    故障现象:80048820


    解决方法:MSN 7.5,adsl路由器,问题出在封包上,路由器的封包长度由1496调到1420后一切就OK 了

    供参考:
    登录路由器-〉网络参数-〉WAN口设置-〉在PPPoE高级设置里,把数据包MTU 1492改成1480。
    此办法也可解决Foxmail无法发送附件和无法在网页邮件中粘贴附件的问题。

    网友提供的其他一些解决方法:


    可能存在以下情况:
    - 您的 Microsoft .NET Passport 设置不正确。
    - 防火墙设置阻止了 MSN Messenger。
    - 安全设置阻止了 MSN Messenger。
    - 您的时间日期设置可能不正确。
    - 一个反病毒程序可能与MSN Messsenger相冲突。
    - 您在使用不正确的密码或电子邮件地址尝试登录。

    请按照所列顺序尝试以下解决方法:
    1. 使用“连接问题疑难解答程序”解决问题。
    a. 启动 MSN Messenger。
    b. 在“工具”菜单上,单击“选项”。
    c. 在“选项”对话框中,单击“连接”,然后在“连接设置”下单击“连接测试”。
    注意:对于MSN Messenger 7.5,单击“连接”,然后在“连接问题疑难解答程序”在单击“开始”。
    d. 按照“连接问题疑难解答程序”中的步骤进行操作。

    2. 确认MSN Messenger是否被防火墙所阻止。请移至http://webmessenger.msn.com/ 登录Web Messenger。点击“启动MSN Web Messenger”确认您是否可以登录。如果可以,那么MSN Messenger有可能被防火墙所阻止。如果您的计算机运行的是第三方(非 Microsoft)软件或防火墙软件(例如,Zone Alarm,Norton网络安全专家,或McAfee),请确保该软件配置为允许 Messenger 运行,然后再次尝试登录 MSN Messenger。请移至http://messenger.msn.com/help/issues.aspx 参阅相关信息。

    3. 通过执行下列操作调整 Internet Explorer 中的代理服务器设置:
    a. 打开 Internet Explorer。
    b. 在“工具”菜单上,单击“Internet 选项”。
    c. 单击“连接”选项卡,然后单击“局域网设置”。
    d. 清除“自动检测设置”复选框。
    e. 单击“确定”,然后再次单击“确定”。

    4. 请按如下步骤在MSN Messenger中清除代理服务器设置:

    -MSN Messenger6.2
    a. 开启MSN Messenger6.2
    b. 在“工具”菜单上单击“选项”。
    c. 在“选项”对话框中单击“连接”选项卡。清除“我使用代理服务器”设置。请不要选择此选项,除非网络管理员建议您这样做。
    d. 连续按两次“确定”。

    -MSN Messenger7.0
    a. 开启MSN Messenger7.0
    b. 单击“工具”菜单上的“选项”。
    c. 在“选项”对话框左侧的主题列表中单击“连接”,然后单击“高级设置”。
    d. 在SOCKS 4下删除内容
    e. 在SOCKS 5下删除内容
    f. 在HTTP代理服务器下删除内容
    g. 连续按两次“确定”保存设置。

    -MSN Messenger7.5
    a. 开启MSN Messenger7.5
    b. 单击“工具”菜单上的“选项”。
    c. 单击“连接”,然后点击“高级设置”
    d. 在SOCKS 下删除内容
    e. 连续按两次“确定”保存设置。

    5. 调整 Microsoft Internet Explorer 安全设置:
    a. 启动 Internet Explorer。
    b. 在“工具”菜单上,单击“Internet 选项”,然后单击“高级”选项卡。
    c. 在“安全”部分,确保选中了以下所有复选框:
    - 检查服务器证书吊销
    - 使用 SSL 2.0
    - 使用 SSL 3.0
    d. 单击“确定”关闭窗口。
    e. 注册 SSL 安全库。要执行此操作,请单击“开始”,单击“运行”,然后按照适用于您的操作系统的步骤进行操作。

    注意 在成功执行每个命令后,您都会收到“DllRegisterServer succeeded.”消息。请在收到此消息后再执行下一条命令。

    - Microsoft Windows XP 和 Microsoft Windows 2000:
    i. 键入 %windir%\system32\REGSVR32 softpub.dll,然后按 ENTER 键。
    ii. 键入 %windir%\system32\REGSVR32 wintrust.dll,然后按 ENTER 键。
    iii. 键入 %windir%\system32\REGSVR32 initpki.dll,然后按 ENTER 键。

    - Microsoft Windows Millennium Edition (Me) 和 Microsoft Windows 98:
    i. 键入 %windir%\system\REGSVR32 softpub.dll,然后按 ENTER 键。
    ii. 键入 %windir%\system\REGSVR32 wintrust.dll,然后按 ENTER 键。
    iii. 键入 %windir%\system\REGSVR32 initpki.dll,然后按 ENTER 键。

    f. 如果您使用的是 Windows XP,请清除安全套接字层 (SSL) 状态和自动完成历史记录:
    i. 启动 Internet Explorer。
    ii. 在“工具”菜单上,单击“Internet 选项”,然后单击“内容”选项卡。
    iii. 在“证书”下,单击“清除 SSL 状态”。
    iv. 收到报告 SSL 缓存成功清除的消息后单击“确定”。

    6. 双击屏幕右下角的时区验证您的计算机的日期和时间设置正确无误。

    7. 请再次尝试登录MSN Messenger

    8. 如果您正在运行反病毒程序,请先关闭,看是否能登录MSN Messenger。如果可以,请联系您的软件制造厂商或查看相关文件如何配置解决此冲突。

    9. 如果您收到“无效的用户名或密码”或“81000303”错误信息,请确保您使用的是正确的用户名和密码。确认您可以使用此帐户登录任何站点,请移至 http://www.passport.com 点击“登录”,如果您可以成功登录,您会看见“登出”按钮。如果失败,请更改您的密码,您可以到http: //memberservices.passport.net/default.srf/ 。 如果此方法有效,尝试再次登录MSN Messenger,请按如下步骤:

    -MSN Messenger7.0或更早的版本
    a. 在MSN Messenger主窗口的“文件”菜单中点击“登录”
    b.输入电子邮件地址和密码
    c.对于Microsoft Windows XP 和Microsoft Server2003,选择“自动登录”,然后按“确定”。
    对于Microsoft Windows98,Microsoft Windows ME,和 Windows2000,选择“在这台电脑上保存我的用户名和密码”,然后按“确定”。

    -MSN Messenger7.5
    a. 在MSN Messenger 登录窗口,先清除“记住我的密码”复选框
    b. 输入密码
    c. 选择“记住我的密码”保存新的密码
    d. 再选择“自动为我登录”

    10. 如果您仍然无法登录MSN Messenger, .NET Messenger服务可能临时不可用。请等待几分钟后再尝试登录。或者移至visit http://messenger.msn.com/status.aspx 查看服务器状态。

    再试试

    @ECHO OFF
    ECHO.如果你msn中修复不了就运行吧.
    ECHO *****************************************************************
    ECHO * This file is provided by msn-problems.com *
    ECHO * Copyright (C) 2004-2005 *
    ECHO *****************************************************************
    ECHO.
    ECHO 等一下.

    REM Following files only needed in windows XP
    IF NOT "%os%"=="Windows_NT" GOTO WIN9X
    regsvr32 Dssenh.dll /s
    regsvr32 Gpkcsp.dll /s
    regsvr32 Slbcsp.dll /s
    regsvr32 Sccbase.dll /s

    :WIN9X
    IF NOT "%os%"=="Windows_NT" CD %windir%\System\
    REM Needed by both XP and 9X
    regsvr32 Softpub.dll /s
    regsvr32 Wintrust.dll /s
    regsvr32 Initpki.dll /s
    regsvr32 Rsaenh.dll /s
    regsvr32 Mssip32.dll /s
    regsvr32 Cryptdlg.dll /s
    regsvr32 Msxml3.dll /s
    ECHO.
    ECHO 搞定,还不可以到这网站的论坛询问 www.msn-problems.com
    ECHO.
    pause

    May 09

    动态添加和删除元素

     
     
    a.html 最后访问的效果demo页
     
    <style>
    .header{height:20px;background:#eee;}
    .ct{margin:4px 0 0 4px;}
    div,ul,li,form{margin:0;padding:0;}
    body{font-size:12px;font-family:'Arial';}
    .expItem{width:400px;border:1px solid #999;}
    .expItem .header{width:400px;}
    .expItem .header span{position:relative;top:2px;}
    .expItem textarea{width:300px;height:80px;}
    </style>
    <script language="javascript">
    var exp="";
    var timer="";
    var expc=0;
    function d(url){
      var b=document.createElement("script");
      b.type="text/javascript";
      b.src=url;
      document.body.appendChild(b);
    }
    function ad(ct,id){
      var d=document.createElement("div");
      d.id=id;
      d.innerHTML=ct;
      document.getElementById("mb").appendChild(d);
      //document.body.appendChild(d);
    }
    function add(it){
      var url="add.php?it="+it;
      if(exp==""){
        d(url);
        try{
          exp=ct;
          clearInterval(timer);
          timer="";
        }catch(e){
          if(timer==""){
            timer=setInterval("add('"+it+"')",200);
          }
          return;
        }
      }
      ad(exp,"exp"+expc);
      expc++;
    }
    function del(id){
      var obj=document.getElementById("exp"+id);
      document.getElementById("mb").removeChild(obj);
      //document.body.removeChild(document.body.lastChild);
    }
    </script>
    <body>
    <a href="javascript:add('exp.html');">addexp</a>
    <a href="javascript:del(0);">del</a>
    dasfasdfasdf
    <div id="mb">
    </div>
    sdfsladkjflskdfj
    sdfasdfs
    sdfsdf
    </body>
     
     
    exp.html 动态现实的内容的页面载体
     
    <div class="expItem"><form action="" method="post"><ul class="header">&nbsp;<span>工作经验</span></ul><ul><div class="ct">公司:<input type="text" name="company"/><br/>职位:<input type="text" name="postion"/><br/>职责:<textarea></textarea><br/></div></ul></form></div>
     
     
    add.php 动态加载内容的后台脚本
     
    <?
    function getItem($url){
      if(!$url)return null;
      $rel=null;
      $fp=fopen($url,"r");
      $rel=fread($fp,filesize($url));
      fclose($fp);
      return $rel;
    }
    $it=$_GET["it"];
    ?>
    var ct='<?=getItem($it)?>';
    April 28

    一些奇怪的 unix 指令名字的由来(转)

    一些奇怪的 unix 指令名字的由来
     
    awk = "Aho Weinberger and Kernighan"

    这个语言以作者 Al Aho, Peter Weinberger 和 Brian Kernighan 的
    姓来命名。

    grep = "Global Regular Expression Print"

    grep 来自 ed 的列印所有符合某 pattern 指令

    g/re/p

    "re" 代表 regular expression

    fgrep = "Fixed GREP".

    fgrep □找固定的字串。"f" 不是代表 "fast" - 事实上, "fgrep
    foobar *.c" 通常比 "egrep foobar *.c" 来得慢(有点意外吧, 不信
    的话, 自己试试喽)。


    尽管如此,Fgrep 仍然有可取之处,在档案中搜寻字串的时候,Fgrep
    能处理的字串数目较 egrep 多。

    egrep = "Extended GREP"

    egrep 用比 grep 更 fancy 的 regular rexpression。许多人始终只
    用 egrep,因为它用的 algorithm 比 grep 或 fgrep 用的高级,而
    且通常是三个程式中最快的。

    cat = "CATenate"

    catenate 是一个艰深难懂的单字,意思是"把它连成一串", 这就是
    "cat" 这个指令对一个或多个档案所做的处理。

    请不要跟 C/A/T 混淆了,C/A/T 是指电脑辅助排版系统(Computer
    Aided Typesetter)。

    gecos = "General Electric Comprehensive Operating Supervisor"

    不过,当通用电器 (GE) 的大型系统部门卖给 Honeywell 的时候,
    Honeywell 就把 GECOS 的 E 拿掉了。

    目前 Unix 的密码档里面仍保有 "pw_gecos" 这个栏位。这个名字是
    从古早的年代沿用过来的。

    Dennis Ritchie 曾经说过:

    "有时候我们会把印表输出或整批工作丢到 GCOS 机器。密码档
    里面的 gcos 栏位是用来隐藏 $IDENT 卡片上的资讯,这样做不
    够优雅"。


    nroff = "New ROFF"
    troff = "Typesetter new ROFF"

    这些字都是从"roff"衍生的, roff 是重写 Multics 上的 runoff 程式得来
    的 (runoff 的意思就是"印出文件")。

    tee = T

    这是管线工人的术语,代表 T 型的管线分叉器。

    bss = "Block Started by Symbol" (由符号启始的区块)

    Dennis Ritchie 曾说过:

    这个缩写也许有其他说法,但事实上我们采用这个缩写的本意是
    "Block Started by Symbol"。它是 FAP 上的虚拟指令,FAP
    (Fortran Assembly [-er?] Program) 是指 IBM 704-709-7090-7094
    这种机型的组译器。这个指令可定义自己的标号,并且预留一定数目
    的字组空间。还有另一个虚拟指令 BES,是 "Block Ended by
    Symbol",跟 BSS 指令几乎一样,不同点在于标号是定义在预留字组
    空间尾端的位址 + 1 的地方。在这些机器上,Fortran 的阵列是以反
    方向储存,而且阵列的索引是从 1 算起。

    这种用法是合理的,因为这跟 UNIX 上标准的程式载入器一样,程式
    码当中并非真的放入这一整块预留空间,而是先用一个数目表示,在
    载入时才真的把所需的预留空间定出来。

    biff = "BIFF"

    这个指令是用来设定当您有新邮件进来时,是否要通知您。这是柏克
    莱大学校园内一只狗的名字。

    我可以确定这个名称的起源,如果您有兴趣的话,Biff 是 Heidi
    Stettner 养的宠物,想当年 Heidi (还有我,跟 Bill Joy) 都还是
    UCB 的研究生时,早期的 BSD 版本还在发展中。Biff 受到流连于
    Evans Halls 这些人的喜爱,也因为它会对前来的邮差吠叫而闻名;因
    此就以 biff 当作指令的名称。
    (这是卡内基美浓大学的 Eric Cooper 证实的)

    rc (像是 ".cshrc" 或 "/etc/rc" 中的 rc 这两个字母) = "RunCom"

    "rc" 是取自 "runcom", 来自麻省理工学院在 1965 年发展的 CTSS
    系统。相关文献曾记载这一段话: '具有从档案中取出一系列命令来执
    行的功能;这称为 "run commands" 又称为 "runcom",而这种档案又
    称为一个 runcom (a runcom)。'

    Brian Kernighan 与 Dennis Ritchie 告诉 Vicki Brown 说: "rc" 也
    是Plan 9 作业系统 shell 的名字。



    Perl = "Practical Extraction and Report Language"
    Perl = "Pathologically Eclectic Rubbish Lister"

    Perl是 Larry Wall 所发展的一种相当受欢迎的语言, Perl 在处文字,
    process,与档案时非常便利,可以说是兼得 shell 与 C 之长。想知道
    更多关于Perl 的讯息,请看 Usenet newsgroup comp.lang.perl。

    Don Libes 的 "Life with Unix" 一书里有更多这类的珍闻轶事。
    April 27

    windows下清除零时文件的程序

    @echo off
    echo 正在清除系统垃圾文件,请稍等......
    del /f /s /q %systemdrive%\*.tmp
    del /f /s /q %systemdrive%\*._mp
    del /f /s /q %systemdrive%\*.log
    del /f /s /q %systemdrive%\*.gid
    del /f /s /q %systemdrive%\*.chk
    del /f /s /q %systemdrive%\*.old
    del /f /s /q %systemdrive%\recycled\*.*
    del /f /s /q %windir%\*.bak
    del /f /s /q %windir%\prefetch\*.*
    rd /s /q %windir%\temp & md %windir%\temp
    del /f /q %userprofile%\cookies\*.*
    del /f /q %userprofile%\recent\*.*
    del /f /s /q "%userprofile%\Local Settings\Temporary Internet Files\*.*"
    del /f /s /q "%userprofile%\Local Settings\Temp\*.*"
    del /f /s /q "%userprofile%\recent\*.*"
    echo 清除系统LJ完成!
    echo. & pause
    February 23

    所谓博客

          坦白说我也不知道博客到底是什么。不过听说是博客的精神是自由和分享。如果抛开了这个精神层面的东西,似乎博客就是某个特定的样式,有日志、相册、档案文件。只要有这些东西就叫博客了。好像中国的博客也都是从外国抄过来的。抄到最后大家都只能通过千篇一律的外观或者功能来鉴别或者标榜自己是个什么东西,是SNS、Blog等等。SNS的精神也许是真正做到社会网络服务,而不是好友和发信息的功能。
         我也曾在国内某知名IT公司工作过,当时我了解的一些部门对产品的概念都是抄袭。小公司为了避免风险和走太多弯路,抄袭大公司的产品如果还有情可原的话。中国的所谓门户却也一味的抄袭韩国、美国甚至在行业内互相抄来抄去,让我觉得工作非常枯燥而且可悲。大家的都省略了思考和创造的过程,直接做了一个合格的产品工人。
          产品的同质现象严重不知道是否也说明的社会的进步,就好像可口可乐和百事可乐,好像麦当劳和肯得基。尽管他们看起来好像都是一样的东西,各方却整天挣扎着去做创新。如果产品方面实在无可修饰了,那么就比比其他。中国的网络产品也是,同质化很严重,可是我却不以为是产品到了无可修饰的地部。
          中国一些博客网火了,新浪就出博客,搜狐就一定也要做博客。新浪出博客因为人家有明星,搜狐也有明星,所以搜狐也出博客了。大家最后都知道两个门户在比着拉人,谁争取了更多明星,谁就争取了更多眼球。博客就是一个名人在个页面里贴一些感怀,照片,好像更像是宣传海报。
          从我周围一些做产品设计的朋友里也大概了解到,中国目前还不需要产品设计。只是需要廉价能加班的工人。因为国外的创意每年都层出不穷,够我们一直抄下去。。。
    February 14

    Ajax & PHP without using the XmlHttpRequest Object(转)

    看到一篇介绍类Ajax技术的,但是不需要xmlhttprequest对象的,大受启发。
    贴下来收藏。
     
    A PHP file which looks something like this:
    <?php

    $html = '<b>This content came from our Ajax Engine</b>';

    ?>

    div = document.getElementById('contentdiv');
    div.innerHTML = '<?php echo $html; ?>';

    When this file is used referenced in a script tag, it will try to set the innerHTML of a div with ID 'contentdiv'. But there's one problem; this file shouldn't be included when the page loads, but only when a button is clicked or some other action. To do this, we must somehow dynamically add a new script tag, which is possible using JavaScript. Something like the following would do the trick:

    // Get base url
    url = document.location.href;
    xend = url.lastIndexOf("/") + 1;
    var base_url = url.substring(0, xend);

    function ajax_do (url) {
            // Does URL begin with http?
            if (url.substring(0, 4) != 'http') {
                    url = base_url + url;
            }

            // Create new JS element
            var jsel = document.createElement('SCRIPT');
            jsel.type = 'text/javascript';
            jsel.src = url;

            // Append JS element (therefore executing the 'AJAX' call)
            document.body.appendChild (jsel);
    }

    It then creates a new script element, using the createElement() function. After that it sets the src attribute of the script element, and adds the script element to the body, effectively 'loading' the file that is referenced by the script element.

    All we need now is a simple page that triggers the Ajax call, i.e.

    <html>
            <head>
                    <title>Demo 1 - The Basic's</title>

                    <script type="text/javascript" src="engine.js"></script>       
            </head>

            <body>
                    <div id="contentdiv">

                    </div>

                    <input type="button" onclick="ajax_do ('page1.php');" value="Get content" />
            </body>
    </html>

     

    January 04

    基于Java的全文索引引擎Lucene简介(转)

    在应用中加入全文检索功能
        ——基于Java的全文索引引擎Lucene简介
     

    作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com

    写于:2002/08 最后更新: 03/16/2005 16:27:52
    Feed Back >> (Read this before you ask question)
    Creative Commons License
    [Blocked Ads]

    版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
    http://www.chedong.com/tech/lucene.html

    关键词:Lucene java full-text search engine Chinese word segment

    内容摘要:

    Lucene是一个基于Java的全文索引工具包。

    1. 基于Java的全文索引引擎Lucene简介:关于作者和Lucene的历史
    2. 全文检索的实现:Luene全文索引和数据库索引的比较
    3. 中文切分词机制简介:基于词库和自动切分词算法的比较
    4. 具体的安装和使用简介:系统结构介绍和演示
    5. Hacking Lucene:简化的查询分析器,删除的实现,定制的排序,应用接口的扩展
    6. 从Lucene我们还可以学到什么

    基于Java的全文索引/检索引擎——Lucene

    Lucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。

    Lucene的作者:Lucene的贡献者Doug Cutting是一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者,后在Excite担任高级系统架构设计师,目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。

    Lucene的发展历程:早先发布在作者自己的www.lucene.com,后来发布在SourceForge,2001年年底成为APACHE基金会jakarta的一个子项目:http://jakarta.apache.org/lucene/

    已经有很多Java项目都使用了Lucene作为其后台的全文索引引擎,比较著名的有:

    • Jive:WEB论坛系统;
    • Eyebrows:邮件列表HTML归档/浏览/查询系统,本文的主要参考文档“TheLucene search engine: Powerful, flexible, and free”作者就是EyeBrows系统的主要开发者之一,而EyeBrows已经成为目前APACHE项目的主要邮件列表归档系统。
    • Cocoon:基于XML的web发布框架,全文检索部分使用了Lucene
    • Eclipse:基于Java的开放开发平台,帮助部分的全文索引使用了Lucene

    对于中文用户来说,最关心的问题是其是否支持中文的全文检索。但通过后面对于Lucene的结构的介绍,你会了解到由于Lucene良好架构设计,对中文的支持只需对其语言词法分析接口进行扩展就能实现对中文检索的支持。

    全文检索的实现机制

    Lucene的API接口设计的比较通用,输入输出结构都很像数据库的表==>记录==>字段,所以很多传统的应用的文件、数据库等都可以比较方便的映射到Lucene的存储结构/接口中。总体上看:可以先把Lucene当成一个支持全文索引的数据库系统

    比较一下Lucene和数据库:

    Lucene 数据库
    索引数据源:doc(field1,field2...) doc(field1,field2...)
    \ indexer /
    _____________
    | Lucene Index|
    --------------
    / searcher \
    结果输出:Hits(doc(field1,field2) doc(field1...))
     索引数据源:record(field1,field2...) record(field1..)
    \ SQL: insert/
    _____________
    | DB Index |
    -------------
    / SQL: select \
    结果输出:results(record(field1,field2..) record(field1...))
    Document:一个需要进行索引的“单元”
    一个Document由多个字段组成
    Record:记录,包含多个字段
    Field:字段 Field:字段
    Hits:查询结果集,由匹配的Document组成 RecordSet:查询结果集,由多个Record组成

    全文检索 ≠ like "%keyword%"

    通常比较厚的书籍后面常常附关键词索引表(比如:北京:12, 34页,上海:3,77页……),它能够帮助读者比较快地找到相关内容的页码。而数据库索引能够大大提高查询的速度原理也是一样,想像一下通过书后面的索引查找的速度要比一页一页地翻内容高多少倍……而索引之所以效率高,另外一个原因是它是排好序的。对于检索系统来说核心是一个排序问题

    由于数据库索引不是为全文索引设计的,因此,使用like "%keyword%"时,数据库索引是不起作用的,在使用like查询时,搜索过程又变成类似于一页页翻书的遍历过程了,所以对于含有模糊查询的数据库服务来说,LIKE对性能的危害是极大的。如果是需要对多个关键词进行模糊匹配:like"%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。

    所以建立一个高效检索系统的关键是建立一个类似于科技索引一样的反向索引机制,将数据源(比如多篇文章)排序顺序存储的同时,有另外一个排好序的关键词列表,用于存储关键词==>文章映射关系,利用这样的映射关系索引:[关键词==>出现关键词的文章编号,出现次数(甚至包括位置:起始偏移量,结束偏移量),出现频率],检索过程就是把模糊查询变成多个可以利用索引的精确查询的逻辑组合的过程。从而大大提高了多关键词查询的效率,所以,全文检索问题归结到最后是一个排序问题。

    由此可以看出模糊查询相对数据库的精确查询是一个非常不确定的问题,这也是大部分数据库对全文检索支持有限的原因。Lucene最核心的特征是通过特殊的索引结构实现了传统数据库不擅长的全文索引机制,并提供了扩展接口,以方便针对不同应用的定制。

    可以通过一下表格对比一下数据库的模糊查询:

      Lucene全文索引引擎 数据库
    索引 将数据源中的数据都通过全文索引一一建立反向索引 对于LIKE查询来说,数据传统的索引是根本用不上的。数据需要逐个便利记录进行GREP式的模糊匹配,比有索引的搜索速度要有多个数量级的下降。
    匹配效果 通过词元(term)进行匹配,通过语言分析接口的实现,可以实现对中文等非英语的支持。 使用:like "%net%" 会把netherlands也匹配出来,
    多个关键词的模糊匹配:使用like "%com%net%":就不能匹配词序颠倒的xxx.net..xxx.com
    匹配度 有匹配度算法,将匹配程度(相似度)比较高的结果排在前面。 没有匹配程度的控制:比如有记录中net出现5词和出现1次的,结果是一样的。
    结果输出 通过特别的算法,将最匹配度最高的头100条结果输出,结果集是缓冲式的小批量读取的。 返回所有的结果集,在匹配条目非常多的时候(比如上万条)需要大量的内存存放这些临时结果集。
    可定制性 通过不同的语言分析接口实现,可以方便的定制出符合应用需要的索引规则(包括对中文的支持) 没有接口或接口复杂,无法定制
    结论 高负载的模糊查询应用,需要负责的模糊查询的规则,索引的资料量比较大 使用率低,模糊匹配规则简单或者需要模糊查询的资料量少

    全文检索和数据库应用最大的不同在于:让最相关的头100条结果满足98%以上用户的需求

    Lucene的创新之处:

    大部分的搜索(数据库)引擎都是用B树结构来维护索引,索引的更新会导致大量的IO操作,Lucene在实现中,对此稍微有所改进:不是维护一个索引文件,而是在扩展索引的时候不断创建新的索引文件,然后定期的把这些新的小索引文件合并到原先的大索引中(针对不同的更新策略,批次的大小可以调整),这样在不影响检索的效率的前提下,提高了索引的效率。

    Lucene和其他一些全文检索系统/应用的比较:

      Lucene 其他开源全文检索系统
    增量索引和批量索引 可以进行增量的索引(Append),可以对于大量数据进行批量索引,并且接口设计用于优化批量索引和小批量的增量索引。 很多系统只支持批量的索引,有时数据源有一点增加也需要重建索引。
    数据源 Lucene没有定义具体的数据源,而是一个文档的结构,因此可以非常灵活的适应各种应用(只要前端有合适的转换器把数据源转换成相应结构), 很多系统只针对网页,缺乏其他格式文档的灵活性。
    索引内容抓取 Lucene的文档是由多个字段组成的,甚至可以控制那些字段需要进行索引,那些字段不需要索引,近一步索引的字段也分为需要分词和不需要分词的类型:
       需要进行分词的索引,比如:标题,文章内容字段
       不需要进行分词的索引,比如:作者/日期字段
    缺乏通用性,往往将文档整个索引了
    语言分析 通过语言分析器的不同扩展实现:
    可以过滤掉不需要的词:an the of 等,
    西文语法分析:将jumps jumped jumper都归结成jump进行索引/检索
    非英文支持:对亚洲语言,阿拉伯语言的索引支持
    缺乏通用接口实现
    查询分析 通过查询分析接口的实现,可以定制自己的查询语法规则:
    比如: 多个关键词之间的 + - and or关系等
     
    并发访问 能够支持多用户的使用  

     

    关于亚洲语言的的切分词问题(Word Segment)

    对于中文来说,全文索引首先还要解决一个语言分析的问题,对于英文来说,语句中单词之间是天然通过空格分开的,但亚洲语言的中日韩文语句中的字是一个字挨一个,所有,首先要把语句中按“词”进行索引的话,这个词如何切分出来就是一个很大的问题。

    首先,肯定不能用单个字符作(si-gram)为索引单元,否则查“上海”时,不能让含有“海上”也匹配。

    但一句话:“北京天安门”,计算机如何按照中文的语言习惯进行切分呢?
    “北京 天安门” 还是“北 京 天安门”?让计算机能够按照语言习惯进行切分,往往需要机器有一个比较丰富的词库才能够比较准确的识别出语句中的单词。

    另外一个解决的办法是采用自动切分算法:将单词按照2元语法(bigram)方式切分出来,比如:
    "北京天安门" ==> "北京 京天 天安 安门"。

    这样,在查询的时候,无论是查询"北京" 还是查询"天安门",将查询词组按同样的规则进行切分:"北京","天安安门",多个关键词之间按与"and"的关系组合,同样能够正确地映射到相应的索引中。这种方式对于其他亚洲语言:韩文,日文都是通用的。

    基于自动切分的最大优点是没有词表维护成本,实现简单,缺点是索引效率低,但对于中小型应用来说,基于2元语法的切分还是够用的。基于2元切分后的索引一般大小和源文件差不多,而对于英文,索引文件一般只有原文件的30%-40%不同,


    自动切分 词表切分
    实现 实现非常简单 实现复杂
    查询 增加了查询分析的复杂程度, 适于实现比较复杂的查询语法规则
    存储效率 索引冗余大,索引几乎和原文一样大 索引效率高,为原文大小的30%左右
    维护成本 无词表维护成本 词表维护成本非常高:中日韩等语言需要分别维护。
    还需要包括词频统计等内容
    适用领域 嵌入式系统:运行环境资源有限
    分布式系统:无词表同步问题
    多语言环境:无词表维护成本
    对查询和存储效率要求高的专业搜索引擎

    目前比较大的搜索引擎的语言分析算法一般是基于以上2个机制的结合。关于中文的语言分析算法,大家可以在Google查关键词"wordsegment search"能找到更多相关的资料。

    安装和使用

    下载:http://jakarta.apache.org/lucene/

    注意:Lucene中的一些比较复杂的词法分析是用JavaCC生成的(JavaCC:JavaCompilerCompiler,纯Java的词法分析生成器),所以如果从源代码编译或需要修改其中的QueryParser、定制自己的词法分析器,还需要从https://javacc.dev.java.net/下载javacc。

    lucene的组成结构:对于外部应用来说索引模块(index)和检索模块(search)是主要的外部应用入口

    org.apache.Lucene.search/ 搜索入口
    org.apache.Lucene.index/ 索引入口
    org.apache.Lucene.analysis/ 语言分析器
    org.apache.Lucene.queryParser/ 查询分析器
    org.apache.Lucene.document/ 存储结构
    org.apache.Lucene.store/  底层IO/存储结构
    org.apache.Lucene.util/ 一些公用的数据结构

    简单的例子演示一下Lucene的使用方法:

    索引过程:从命令行读取文件名(多个),将文件分路径(path字段)和内容(body字段)2个字段进行存储,并对内容进行全文索引:索引的单位是Document对象,每个Document对象包含多个字段Field对象,针对不同的字段属性和数据输出的需求,对字段还可以选择不同的索引/存储字段规则,列表如下:
    方法 切词 索引 存储 用途
    Field.Text(String name, String value) Yes Yes Yes 切分词索引并存储,比如:标题,内容字段
    Field.Text(String name, Reader value) Yes Yes No 切分词索引不存储,比如:META信息,
    不用于返回显示,但需要进行检索内容
    Field.Keyword(String name, String value) No Yes Yes 不切分索引并存储,比如:日期字段
    Field.UnIndexed(String name, String value) No No Yes 不索引,只存储,比如:文件路径
    Field.UnStored(String name, String value) Yes Yes No 只全文索引,不存储
    public class IndexFiles { 
    //使用方法:: IndexFiles [索引输出目录] [索引的文件列表] ...
    public static void main(String[] args) throws Exception {
    String indexPath = args[0];
    IndexWriter writer;
    //用指定的语言分析器构造一个新的写索引器(第3个参数表示是否为追加索引)
    writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);

    for (int i=1; i<args.length; i++) {
    System.out.println("Indexing file " + args[i]);
    InputStream is = new FileInputStream(args[i]);

    //构造包含2个字段Field的Document对象
    //一个是路径path字段,不索引,只存储
    //一个是内容body字段,进行全文索引,并存储
    Document doc = new Document();
    doc.add(Field.UnIndexed("path", args[i]));
    doc.add(Field.Text("body", (Reader) new InputStreamReader(is)));
    //将文档写入索引
    writer.addDocument(doc);
    is.close();
    };
    //关闭写索引器
    writer.close();
    }
    }
     

    索引过程中可以看到:

    • 语言分析器提供了抽象的接口,因此语言分析(Analyser)是可以定制的,虽然lucene缺省提供了2个比较通用的分析器SimpleAnalyser和StandardAnalyser,这2个分析器缺省都不支持中文,所以要加入对中文语言的切分规则,需要修改这2个分析器。
    • Lucene并没有规定数据源的格式,而只提供了一个通用的结构(Document对象)来接受索引的输入,因此输入的数据源可以是:数据库,WORD文档,PDF文档,HTML文档……只要能够设计相应的解析转换器将数据源构造成成Docuement对象即可进行索引。
    • 对于大批量的数据索引,还可以通过调整IndexerWrite的文件合并频率属性(mergeFactor)来提高批量索引的效率。

    检索过程和结果显示:

    搜索结果返回的是Hits对象,可以通过它再访问Document==>Field中的内容。

    假设根据body字段进行全文检索,可以将查询结果的path字段和相应查询的匹配度(score)打印出来,

    public class Search { 
    public static void main(String[] args) throws Exception {
    String indexPath = args[0], queryString = args[1];
    //指向索引目录的搜索器
    Searcher searcher = new IndexSearcher(indexPath);
    //查询解析器:使用和索引同样的语言分析器
    Query query = QueryParser.parse(queryString, "body",
    new SimpleAnalyzer());
    //搜索结果使用Hits存储
    Hits hits = searcher.search(query);
    //通过hits可以访问到相应字段的数据和查询的匹配度
    for (int i=0; i<hits.length(); i++) {
    System.out.println(hits.doc(i).get("path") + "; Score: " +
    hits.score(i));
    };
    }
    }
    在整个检索过程中,语言分析器,查询分析器,甚至搜索器(Searcher)都是提供了抽象的接口,可以根据需要进行定制。

    Hacking Lucene

    简化的查询分析器

    个人感觉lucene成为JAKARTA项目后,画在了太多的时间用于调试日趋复杂QueryParser,而其中大部分是大多数用户并不很熟悉的,目前LUCENE支持的语法:

    Query ::= ( Clause )*
    Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")")

    中间的逻辑包括:and or + - &&||等符号,而且还有"短语查询"和针对西文的前缀/模糊查询等,个人感觉对于一般应用来说,这些功能有一些华而不实,其实能够实现目前类似于Google的查询语句分析功能其实对于大多数用户来说已经够了。所以,Lucene早期版本的QueryParser仍是比较好的选择。

    添加修改删除指定记录(Document)

    Lucene提供了索引的扩展机制,因此索引的动态扩展应该是没有问题的,而指定记录的修改也似乎只能通过记录的删除,然后重新加入实现。如何删除指定的记录呢?删除的方法也很简单,只是需要在索引时根据数据源中的记录ID专门另建索引,然后利用IndexReader.delete(Termterm)方法通过这个记录ID删除相应的Document。

    根据某个字段值的排序功能

    lucene缺省是按照自己的相关度算法(score)进行结果排序的,但能够根据其他字段进行结果排序是一个在LUCENE的开发邮件列表中经常提到的问题,很多原先基于数据库应用都需要除了基于匹配度(score)以外的排序功能。而从全文检索的原理我们可以了解到,任何不基于索引的搜索过程效率都会导致效率非常的低,如果基于其他字段的排序需要在搜索过程中访问存储字段,速度回大大降低,因此非常是不可取的。

    但这里也有一个折中的解决方法:在搜索过程中能够影响排序结果的只有索引中已经存储的docID和score这2个参数,所以,基于score以外的排序,其实可以通过将数据源预先排好序,然后根据docID进行排序来实现。这样就避免了在LUCENE搜索结果外对结果再次进行排序和在搜索过程中访问不在索引中的某个字段值。

    这里需要修改的是IndexSearcher中的HitCollector过程:

    ...
     scorer.score(new HitCollector() {
    private float minScore = 0.0f;
    public final void collect(int doc, float score) {
    if (score > 0.0f && // ignore zeroed buckets
    (bits==null || bits.get(doc))) { // skip docs not in bits
    totalHits[0]++;
    if (score >= minScore) {
    /* 原先:Lucene将docID和相应的匹配度score例入结果命中列表中:
    * hq.put(new ScoreDoc(doc, score)); // update hit queue
    * 如果用doc 或 1/doc 代替 score,就实现了根据docID顺排或逆排
    * 假设数据源索引时已经按照某个字段排好了序,而结果根据docID排序也就实现了
    * 针对某个字段的排序,甚至可以实现更复杂的score和docID的拟合。
    */
    hq.put(new ScoreDoc(doc, (float) 1/doc ));
    if (hq.size() > nDocs) { // if hit queue overfull
    hq.pop(); // remove lowest in hit queue
    minScore = ((ScoreDoc)hq.top()).score; // reset minScore
    }
    }
    }
    }
    }, reader.maxDoc());

    更通用的输入输出接口

    虽然lucene没有定义一个确定的输入文档格式,但越来越多的人想到使用一个标准的中间格式作为Lucene的数据导入接口,然后其他数据,比如PDF只需要通过解析器转换成标准的中间格式就可以进行数据索引了。这个中间格式主要以XML为主,类似实现已经不下4,5个:

    数据源: WORD       PDF     HTML    DB       other
    \ | | | /
    XML中间格式
    |
    Lucene INDEX

    目前还没有针对MSWord文档的解析器,因为Word文档和基于ASCII的RTF文档不同,需要使用COM对象机制解析。这个是我在Google上查的相关资料:http://www.intrinsyc.com/products/enterprise_applications.asp
    另外一个办法就是把Word文档转换成text:http://www.winfield.demon.nl/index.html


    索引过程优化

    索引一般分2种情况,一种是小批量的索引扩展,一种是大批量的索引重建。在索引过程中,并不是每次新的DOC加入进去索引都重新进行一次索引文件的写入操作(文件I/O是一件非常消耗资源的事情)。

    Lucene先在内存中进行索引操作,并根据一定的批量进行文件的写入。这个批次的间隔越大,文件的写入次数越少,但占用内存会很多。反之占用内存少,但文件IO操作频繁,索引速度会很慢。在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造索引器后根据应用环境的情况充分利用内存减少文件的操作。根据我的使用经验:缺省Indexer是每20条记录索引后写入一次,每将MERGE_FACTOR增加50倍,索引速度可以提高1倍左右。

    搜索过程优化

    lucene支持内存索引:这样的搜索比基于文件的I/O有数量级的速度提升。
    http://www.onjava.com/lpt/a/3273
    而尽可能减少IndexSearcher的创建和对搜索结果的前台的缓存也是必要的。

    Lucene面向全文检索的优化在于首次索引检索后,并不把所有的记录(Document)具体内容读取出来,而起只将所有结果中匹配度最高的头100条结果(TopDocs)的ID放到结果集缓存中并返回,这里可以比较一下数据库检索:如果是一个10,000条的数据库检索结果集,数据库是一定要把所有记录内容都取得以后再开始返回给应用结果集的。所以即使检索匹配总数很多,Lucene的结果集占用的内存空间也不会很多。对于一般的模糊检索应用是用不到这么多的结果的,头100条已经可以满足90%以上的检索需求。

    如果首批缓存结果数用完后还要读取更后面的结果时Searcher会再次检索并生成一个上次的搜索缓存数大1倍的缓存,并再重新向后抓取。所以如果构造一个Searcher去查1-120条结果,Searcher其实是进行了2次搜索过程:头100条取完后,缓存结果用完,Searcher重新检索再构造一个200条的结果缓存,依此类推,400条缓存,800条缓存。由于每次Searcher对象消失后,这些缓存也访问那不到了,你有可能想将结果记录缓存下来,缓存数尽量保证在100以下以充分利用首次的结果缓存,不让Lucene浪费多次检索,而且可以分级进行结果缓存。

    Lucene的另外一个特点是在收集结果的过程中将匹配度低的结果自动过滤掉了。这也是和数据库应用需要将搜索的结果全部返回不同之处。

    我的一些尝试

    • 支持中文的Tokenizer:这里有2个版本,一个是通过JavaCC生成的,对CJK部分按一个字符一个TOKEN索引,另外一个是从SimpleTokenizer改写的,对英文支持数字和字母TOKEN,对中文按迭代索引。
    • 基于XML数据源的索引器:XMLIndexer,因此所有数据源只要能够按照DTD转换成指定的XML,就可以用XMLIndxer进行索引了。
    • 根据某个字段排序:按记录索引顺序排序结果的搜索器:IndexOrderSearcher,因此如果需要让搜索结果根据某个字段排序,可以让数据源先按某个字段排好序(比如:PriceField),这样索引后,然后在利用这个按记录的ID顺序检索的搜索器,结果就是相当于是那个字段排序的结果了。

    从Lucene学到更多

    Luene的确是一个面对对象设计的典范

    • 所有的问题都通过一个额外抽象层来方便以后的扩展和重用:你可以通过重新实现来达到自己的目的,而对其他模块而不需要;
    • 简单的应用入口Searcher, Indexer,并调用底层一系列组件协同的完成搜索任务;
    • 所有的对象的任务都非常专一:比如搜索过程:QueryParser分析将查询语句转换成一系列的精确查询的组合(Query),通过底层的索引读取结构IndexReader进行索引的读取,并用相应的打分器给搜索结果进行打分/排序等。所有的功能模块原子化程度非常高,因此可以通过重新实现而不需要修改其他模块。 
    • 除了灵活的应用接口设计,Lucene还提供了一些适合大多数应用的语言分析器实现(SimpleAnalyser,StandardAnalyser),这也是新用户能够很快上手的重要原因之一。

    这些优点都是非常值得在以后的开发中学习借鉴的。作为一个通用工具包,Lunece的确给予了需要将全文检索功能嵌入到应用中的开发者很多的便利。

    此外,通过对Lucene的学习和使用,我也更深刻地理解了为什么很多数据库优化设计中要求,比如:

    • 尽可能对字段进行索引来提高查询速度,但过多的索引会对数据库表的更新操作变慢,而对结果过多的排序条件,实际上往往也是性能的杀手之一。
    • 很多商业数据库对大批量的数据插入操作会提供一些优化参数,这个作用和索引器的merge_factor的作用是类似的,
    • 20%/80%原则:查的结果多并不等于质量好,尤其对于返回结果集很大,如何优化这头几十条结果的质量往往才是最重要的。
    • 尽可能让应用从数据库中获得比较小的结果集,因为即使对于大型数据库,对结果集的随机访问也是一个非常消耗资源的操作。

    参考资料:

    Apache: Lucene Project
    http://jakarta.apache.org/lucene/
    Lucene开发/用户邮件列表归档
    Lucene-dev@jakarta.apache.org
    Lucene-user@jakarta.apache.org

    The Lucene search engine: Powerful, flexible, and free
    http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-Lucene_p.html

    Lucene Tutorial
    http://www.darksleep.com/puff/lucene/lucene.html

    Notes on distributed searching with Lucene
    http://home.clara.net/markharwood/lucene/

    中文语言的切分词
    http://www.google.com/search?sourceid=navclient&hl=zh-CN&q=chinese+word+segment

    搜索引擎工具介绍
    http://searchtools.com/

    Lucene作者Cutting的几篇论文和专利
    http://lucene.sourceforge.net/publications.html 

    Lucene的.NET实现:dotLucene
    http://sourceforge.net/projects/dotlucene/

    Lucene作者Cutting的另外一个项目:基于Java的搜索引擎Nutch
    http://www.nutch.org/   http://sourceforge.net/projects/nutch/

    关于基于词表和N-Gram的切分词比较
    http://china.nikkeibp.co.jp/cgi-bin/china/news/int/int200302100112.html

    2005-01-08 Cutting在Pisa大学做的关于Lucene的讲座:非常详细的Lucene架构解说

    特别感谢:
    前网易CTO许良杰(Jack Xu)给我的指导:是您将我带入了搜索引擎这个行业。

    December 28

    中文排版CSS心得(转)

    焦延伍 | 学习制作 | 出处:教程

    数月来学习web标准,并遵循标准设计和制作web页面。一直想写点什么,整理一下自己的心得体会。写这篇文章,主要是针对中文排版设计,英文排版因为很少做,所以不涉及。

    先介绍如何设定字体、颜色、大小、段落空白等比较简单的应用,后面再介绍下比如首字下沉、首行缩进。最后讲一些常用的web页面中文排版,比如中文字的截断、固定宽度词内折行(word-wrap和word-break)等等。因为只是写一些应用方面的心得,如果需要完整的CSS属性介绍,请参考CSS手册。

    1、如何设定文字字体、颜色、大小 —— 使用font

    font-style设定斜体,比如font-style: italic;
    font-weight设定文字粗细,比如font-weight: bold;
    font-size设定文字大小,比如font-size: 12px;(或者9pt,不同单位显示问题参考CSS手册)
    line-height设定行距,比如line-height: 150%;
    color设定文字颜色(注意不是font-color),比如color: red;
    font-family设定字体,比如font-family : "Lucida Grande", Verdana, Lucida, Arial, Helvetica, 宋体,sans-serif;(这是通用的写法)

    以上都可以写在一行font属性里(除了color属性需要单独写):
    font: italic bold 12px/150% "Lucida Grande", Verdana, Lucida, Arial, Helvetica, 宋体,sans-serif;

    2、如何控制段落排版 —— 使用margin,text-align

    中文段落使用<p>标签,左右(相当于缩进)、段前段后的空白,都可以用margin。比如:
    p{
     margin: 18px 6px 6px 18px; /*分别是上、右、下、左,十二点开始的顺时针方向*/
    }
    文字的对齐方式用text-align,比如:
    p{
     text-align: center;  /*居中对齐*/
    }
    对齐方式还有left、right和justify(两端对齐)

    PS.谈起margin,我习惯于在写CSS的时候为所有的标签定义margin: 0; 因为时而出现由于默认的margin值导致页面排版问题,而自己找不到原因(特别注意的是ul/ol/p/dt/dd等标签)

    3、竖排文字 —— 使用writing-mode

    writing-mode属性有两个值lr-tb和tb-rl,前者是默认的左-右、上-下,后者是上-下、右-左。
    比如:
    p{
     writing-mode: tb-rl;
    }
    可以结合direction排版。

    4、项目符号的问题 —— 使用list-style

    在CSS里项目符号有disc(实心圆点)、circle(空心圆圈)、square(实心方块)、decimal(阿拉伯数字)、lower-roman(小写罗马数字)、upper-roman(大写罗马数字)、lower-alpha(小写英文字母)、upper-alpha(大写英文字母)、none(无)。比如设定一个列表(ul或ol)的项目符号为方块,如:
    li{
     list-style: square;
    }
    另外list-style还有一些值,比如可以采用一些小图片作为项目符号,在list-style下直接写url(“图片地址”)就可以了。注意如果一个项目列表的左外补丁(margin-left)设为零的时候,list-style-position: outside(默认是outside)的项目符号不会显示。可惜的是上述的项目符号似乎并不能设定大小,圆点和方块始终是那么点。并且不能设定垂直方向上的对齐。

    5、首字下沉 —— 使用:first-letter

    伪对象:first-letter配合font-size、float可以制作首字下沉效果。
    比如:
    p:first-letter{
     padding: 6px;
     font-size: 32pt;
     float: left;
    }

    6、首行缩进 —— 使用text-indent

    text-indent可以使得容器内首行缩进一定单位。比如中文段落一般每段前空两个汉字。可以这么写:
    p{
     text-indent: 2em; /*em是相对单位,2em即现在一个字大小的两倍*/
    }
    如果font-size是12px的话,那么text-indent: 2em则缩进24px。

    7、关于汉字注音 —— 使用ruby标签和ruby-align属性

    比如说<ruby>注音<rt style="font-size: 11px;">zhu yin</rt></ruby>,可以利用ruby-align设置对齐方式。这是在CSS手册里面看到的,具体可以自行查阅ruby-align项。

    8、固定宽度汉字截断 —— 使用text-overflow

    用后台语言可以对从数据库里的字段内容做截断处理,比如说截12个汉字(之后用省略号)。但是有时还需要html标签的过滤等,而用CSS来控制则没有这个问题。比如对列表应用以下样式:
    li{
     overflow:hidden;
     text-overflow:ellipsis;
     white-space:nowrap;
    }
    不过只能处理文字在一行上的截断,不能处理多行。

    9、固定宽度汉字(词)折行 —— 使用word-break

    举个例子,比如说要在一个固定宽度容器里面显示很多地名(假设以空格分隔),为了避免地名中间断开(即一个字在上面而另一个字折断到下一行去了)。则可以使用word-break。比如:
    <div style="width:210px;height: 200px;background: #ccc;word-break:keep-all">
    南京上海 上海上 南 上海上海 南京 上海上海上海 南京上海 上海 南京上海 上海 南京 上海 南京 上海 南京 上海 南京 上海 南京 上海 南京上海 上海 南京上海 上海
    </div>
    值得注意的是里面的空格不能以&nbsp;代替(最少要有一个软空格)。

    CSS的十八般技巧(转)

    好文一定要收藏。(游泳的鱼按)

    • 翻译:阿捷
    • 原文作者:Roger Johansson
    • 作者简介:住在瑞典哥德堡,1994年开始接触和参与web设计,456 Berea Street是他的住址,因此采用这个名字作为他的个人主页域名
    • 原文出处:www.456bereastreet.com
    • 原文发表时间:2005年3月15日
    • 阿捷说明:此文原名"CSS tips and tricks",有2篇,我将它们合并翻译在本文中。

    最近,经常有朋友问我一些工作中遇到的CSS问题。他们总是不能很好的控制CSS,影响CSS的效率发挥。我来分析总结一下错误所在,帮助大家更加容易使用CSS。

    本文总结了我开始使用CSS布局方法以来所有的技巧和兼容方案,我愿意把这些与你分享,我会重点解释一些新手容易犯的错误(包括我自己也犯过的),如果你已经是CSS高手,这些经验技巧可能已经都知道,如果你有更多的,希望可以帮我补充。

    一.使用css缩写

    使用缩写可以帮助减少你CSS文件的大小,更加容易阅读。css缩写的主要规则请参看《常用css缩写语法总结》,这里就不展开描述。

    二.明确定义单位,除非值为0

    忘记定义尺寸的单位是CSS新手普遍的错误。在HTML中你可以只写width="100",但是在CSS中,你必须给一个准确的单位,比如:width:100px width:100em。只有两个例外情况可以不定义单位:行高和0值。除此以外,其他值都必须紧跟单位,注意,不要在数值和单位之间加空格。

    三.区分大小写

    当在XHTML中使用CSS,CSS里定义的元素名称是区分大小写的。为了避免这种错误,我建议所有的定义名称都采用小写。

    class和id的值在HTML和XHTML中也是区分大小写的,如果你一定要大小写混合写,请仔细确认你在CSS的定义和XHTML里的标签是一致的。

    四.取消class和id前的元素限定

    当你写给一个元素定义class或者id,你可以省略前面的元素限定,因为ID在一个页面里是唯一的,而clas s可以在页面中多次使用。你限定某个元素毫无意义。例如:

    div#content { /* declarations */ }
    fieldset.details { /* declarations */ }

    可以写成

    #content { /* declarations */ }
    .details { /* declarations */ }

    这样可以节省一些字节。

    五.默认值

    通常padding的默认值为0,background-color的默认值是transparent。但是在不同的浏览器默认值可能不同。如果怕有冲突,可以在样式表一开始就先定义所有元素的margin和padding值都为0,象这样:

    * {
    margin:0;
    padding:0;
    }

    六.不需要重复定义可继承的值

    CSS中,子元素自动继承父元素的属性值,象颜色、字体等,已经在父元素中定义过的,在子元素中可以直接继承,不需要重复定义。但是要注意,浏览器可能用一些默认值覆盖你的定义。

    七.最近优先原则

    如果对同一个元素的定义有多种,以最接近(最小一级)的定义为最优先,例如有这么一段代码

    Update: Lorem ipsum dolor set

    在CSS文件中,你已经定义了元素p,又定义了一个class"update"

    p {
    margin:1em 0;
    font-size:1em;
    color:#333;
    }
    .update {
    font-weight:bold;
    color:#600;
    }

    这两个定义中,class="update"将被使用,因为class比p更近。你可以查阅W3C的《 Calculating a selector’s specificity》 了解更多。

    八.多重class定义

    一个标签可以同时定义多个class。例如:我们先定义两个样式,第一个样式背景为#666;第二个样式有10 px的边框。

    .one{width:200px;background:#666;}
    .two{border:10px solid #F00;}

    在页面代码中,我们可以这样调用

    <div class="one two"></div>

    这样最终的显示效果是这个div既有#666的背景,也有10px的边框。是的,这样做是可以的,你可以尝试一下。

    九.使用子选择器(descendant selectors)

    CSS初学者不知道使用子选择器是影响他们效率的原因之一。子选择器可以帮助你节约大量的class定义。我们来看下面这段代码:

    <div id="subnav">
    <ul>
    <li class="subnavitem"> <a href="#" class="subnavitem">Item 1</a></li>>
    <li class="subnavitemselected"> <a href="#" class="subnavitemselected"> Item 1</a> </li>
    <li class="subnavitem"> <a href="#" class="subnavitem"> Item 1</a> </li>
    </ul>
    </div>

    这段代码的CSS定义是:

    div#subnav ul { /* Some styling */ }
    div#subnav ul li.subnavitem { /* Some styling */ }
    div#subnav ul li.subnavitem a.subnavitem { /* Some styling */ }
    div#subnav ul li.subnavitemselected { /* Some styling */ }
    div#subnav ul li.subnavitemselected a.subnavitemselected { /* Some styling */ }

    你可以用下面的方法替代上面的代码

    <ul id="subnav">
    <li> <a href="#"> Item 1</a> </li>
    <li class="sel"> <a href="#"> Item 1</a> </li>
    <li> <a href="#"> Item 1</a> </li>
    </ul>

    样式定义是:

    #subnav { /* Some styling */ }
    #subnav li { /* Some styling */ }
    #subnav a { /* Some styling */ }
    #subnav .sel { /* Some styling */ }
    #subnav .sel a { /* Some styling */ }

    用子选择器可以使你的代码和CSS更加简洁、更加容易阅读。

    十.不需要给背景图片路径加引号

    为了节省字节,我建议不要给背景图片路径加引号,因为引号不是必须的。例如:

    background:url("images/***.gif") #333;

    可以写为

    background:url(images/***.gif) #333;

    如果你加了引号,反而会引起一些浏览器的错误。

    十一.组选择器(Group selectors)

    当一些元素类型、class或者id都有共同的一些属性,你就可以使用组选择器来避免多次的重复定义。这可以节省不少字节。

    例如:定义所有标题的字体、颜色和margin,你可以这样写:

    h1,h2,h3,h4,h5,h6 {
    font-family:"Lucida Grande",Lucida,Arial,Helvetica,sans-serif;
    color:#333;
    margin:1em 0;
    }

    如果在使用时,有个别元素需要定义独立样式,你可以再加上新的定义,可以覆盖老的定义,例如:

    h1 { font-size:2em; }
    h2 { font-size:1.6em; }

    十二.用正确的顺序指定链接的样式

    当你用CSS来定义链接的多个状态样式时,要注意它们书写的顺序,正确的顺序是::link :visited :hover :active。抽取第一个字母是"LVHA",你可以记忆成"LoVe HAte"(喜欢讨厌)。为什么这么定义,可以参考Eric Meyer的《Link Specificity》。

    如果你的用户需要用键盘来控制,需要知道当前链接的焦点,你还可以定义:focus属性。:focus属性的效果也取决与你书写的位置,如果你希望聚焦元素显示:hover效果,你就把:focus写在:hover前面;如果你希望聚焦效果替代:hover效果,你就把:focus放在:hover后面。

    十三.清除浮动

    一个非常常见的CSS问题,定位使用浮动的时候,下面的层被浮动的层所覆盖,或者层里嵌套的子层超出了外层的范围。

    通常的解决办法是在浮动层后面添加一个额外元素,例如一个div或者一个br,并且定义它的样式为clear: both。这个办法有一点牵强,幸运的是还有一个好办法可以解决,参看这篇文章《How To Clear Floats Without Structural Markup》(注:本站将尽快翻译此文)。

    上面2种方法可以很好解决浮动超出的问题,但是如果当你真的需要对层或者层里的对象进行clear的时候怎么办?一种简单的方法就是用overflow属性,这个方法最初的发表在《Simple Clearing of Floats》,又在《Clearance》和《Super simple clearing floats》中被广泛讨论。

    上面那一种clear方法更适合你,要看具体的情况,这里不再展开论述。另外关于float的应用,一些优秀的文章已经说得很清楚,推荐你阅读:《Floatutorial》、《Containing Floats》和《Float Layouts

    十四.横向居中(centering)

    这是一个简单的技巧,但是值得再说一遍,因为我看见太多的新手问题都是问这个:CSS如何横向居中?你需要定义元素的宽,并且定义横向的margin,如果你的布局包含在一个层(容器)中,就象这样:

    你可以这样定义使它横向居中:

    #wrap {
    width:760px; /* 修改为你的层的宽度 */
    margin:0 auto;
    }

    但是IE5/Win不能正确显示这个定义,我们采用一个非常有用的技巧来解决:用text-align属性。就象这样:

    body {
    text-align:center;
    }
    #wrap {
    width:760px; /* 修改为你的层的宽度 */
    margin:0 auto;
    text-align:left;
    }

    第一个body的text-align:center; 规则定义IE5/Win中body的所有元素居中(其他浏览器只是将文字居中) ,第二个text-align:left;是将#warp中的文字居左。

    十五.导入(Import)和隐藏CSS

    因为老版本浏览器不支持CSS,一个通常的做法是使用@import技巧来把CSS隐藏起来。例如:

    @import url("main.css");

    然而,这个方法对IE4不起作用,这让我很是头疼了一阵子。后来我用这样的写法:

    @import "main.css";

    这样就可以在IE4中也隐藏CSS了,呵呵,还节省了5个字节呢。想了解@import语法的详细说明,可以看这里《centricle’s css filter chart

    十六.针对IE的优化

    有些时候,你需要对IE浏览器的bug定义一些特别的规则,这里有太多的CSS技巧(hacks),我只使用其中的两种方法,不管微软在即将发布的IE7 beta版里是否更好的支持CSS,这两种方法都是最安全的。

    • 1.注释的方法
      • (a)在IE中隐藏一个CSS定义,你可以使用子选择器(child selector):
        html>body p {
        /* 定义内容 */
        }
      • (b)下面这个写法只有IE浏览器可以理解(对其他浏览器都隐藏)
        * html p {
        /* declarations */
        }
      • (c)还有些时候,你希望IE/Win有效而IE/Mac隐藏,你可以使用"反斜线"技巧:
        /* \*/
        * html p {
        declarations
        }
        /* */
    • 2.条件注释(conditional comments)的方法

      另外一种方法,我认为比CSS Hacks更加经得起考验就是采用微软的私有属性条件注释(conditional comments)。用这个方法你可以给IE单独定义一些样式,而不影响主样式表的定义。就象这样:

      <!--[if IE]>
      <link rel="stylesheet" type="text/css" href="ie.css" />
      <![endif]-->

    十七.调试技巧:层有多大?

    当调试CSS发生错误,你就要象排版工人,逐行分析CSS代码。我通常在出问题的层上定义一个背景颜色,这样就能很明显看到层占据多大空间。有些人建议用border,一般情况也是可以的,但问题是,有时候border 会增加元素的尺寸,border-top和boeder-bottom会破坏纵向margin的值,所以使用background更加安全些。

    另外一个经常出问题的属性是outline。outline看起来象boeder,但不会影响元素的尺寸或者位置。只有少数浏览器支持outline属性,我所知道的只有Safari、OmniWeb、和Opera。

    十八.CSS代码书写样式

    在写CSS代码的时候,对于缩进、断行、空格,每个人有每个人的书写习惯。在经过不断实践后,我决定采用下面这样的书写样式:

    selector1,
    selector2 {
    property:value;
    }

    当使用联合定义时,我通常将每个选择器单独写一行,这样方便在CSS文件中找到它们。在最后一个选择器和大括号{之间加一个空格,每个定义也单独写一行,分号直接在属性值后,不要加空格。

    我习惯在每个属性值后面都加分号,虽然规则上允许最后一个属性值后面可以不写分号,但是如果你要加新样式时容易忘记补上分号而产生错误,所以还是都加比较好。

    最后,关闭的大括号}单独写一行。

    空格和换行有助与阅读。

    终于寻到了javascript操作xml

    这部分是代码,其中DataSet是从他人的blog上抄来的。
    而那个人也标明是转,无法严明出处,只好不写作者的名字了。
    在此说声非常抱歉。
     
    mozzila部分兼容的代码和得到xmldoc还有部分代码是我加的。
    让这个东西可以工作起来。
     
    <script language="javascript">
    //类的构造,传入xml文档和需要处理的标签名称
    function DataSet(xmlFile, tagLabel) {
      var xmldoc;
      if(window.ActiveXObject){
        xmldoc=new ActiveXObject("Microsoft.XMLDOM");
      }else if(document.implementation&&document.implementation.createDocument){
        xmldoc=document.implementation.createDocument("","doc",null);
      }
      xmldoc.async = false;
      xmldoc.load(xmlFile);
      this.rootObj = xmldoc.getElementsByTagName(tagLabel)
     
      this.getCount = getCount;
      this.getData = getData;
      this.getAttribute = getAttribute;
      this.getNodeAttribute=getNodeAttribute;
    }
    function getCount(){
      return this.rootObj.length
    }
    function getData(index, tagName){
      if (index >= this.count) return "index overflow"
      var node = this.rootObj[index]
      var str = node.getElementsByTagName(tagName)[0].firstChild.data
      return str
    }
    function getAttribute(index, tagName) {
      if (index >= this.count) return "index overflow"
      var node = this.rootObj[index]
      var str = node.getAttribute(tagName)
      return str
    }
    function getNodeAttribute(index,node,tagName){
      if(index>=this.rootObj[index].childNodes.length)return "index overflow";
      var str=this.rootObj[index].childNodes[node].getAttribute(tagName);
      return str;
    }
    var set=new DataSet("pubdate.xml","pubdates");
    //alert(set.getCount());
    alert(set.getAttribute(2,"name"));
    alert(set.getData(1,"job"));
    </script>
     
    下面是data.xml,从网上找了个现成的。呵呵。
    <?xml version="1.0" encoding="gb2312"?>
    <employees>
         <employee name="Billgates">
              <job>Programmer</job>
              <salary>32768</salary>
         </employee>
         <employee name="王涛">
              <job>无业游民</job>
              <salary>70000</salary>
         </employee>
         <employee name="Big 中华">
              <job>哈尔滨CEO</job>
              <salary>100000</salary>
         </employee>
    </employees>
     
    December 27

    javascript实现urlencode和urldecode

    下面是用js实现的urlencode方法,urldecode方法。
    urlencode和spell方法是其他大大写的。
    urldecode方法是我根据urlencode方法补充的。
    这下全套够用啦。嘿嘿。
    支持ie和mozzila,firefox,opera。
     
    function UrlEncode(str){
     var i,c,ret="",strSpecial="!\"#$%&'()*+,/:;<=>?@[\]^`{|}~%";
     for(i=0;i<str.length;i++){
      if(str.charCodeAt(i)>=0x4e00){
       c=qswhU2GB[str.charCodeAt(i)-0x4e00];
       ret+="%"+c.slice(0,2)+"%"+c.slice(-2);
      }else{
       c=str.charAt(i);
       if(c==" ")
        ret+="+";
       else if(strSpecial.indexOf(c)!=-1)
        ret+="%"+str.charCodeAt(i).toString(16);
       else
        ret+=c;
      }
     }
     return ret;
    }
    function UrlDecode(str){
      var i,c,d,t,p,ret="";
      function findPos(str){
        for(var j=0;j<qswhU2GB.length;j++){
          if(qswhU2GB[j]==str){return j;}
        }
        return -1;
      }
      for(i=0;i<str.length;){
        c=str.charAt(i);i++;
        if(c!="%"){
          if(c=="+"){
            ret+=" ";
          }else{
            ret+=c;
          }
        }else{
          t=str.substring(i,i+2);i+=2;
          if(("0x"+t)>0xA0){
            d=str.substring(i+1,i+3);i+=3;
            p=findPos(t+d);
            if(p!=-1){
              ret+=String.fromCharCode(p+0x4e00);
            }
          }else{
            ret+=String.fromCharCode("0x"+t);
          }
        }
      }
      return ret;
    }
    竟然说我贴太多了。
    对照数组我再贴一个。
    December 02

    关于CPU(转自和讯)

    1.主频

      主频也叫时钟频率,单位是MHz,用来表示CPU的运算速度。CPU的主频=外频×倍频系数。很多人认为主频就决定着CPU的运行速度,这不仅是个片面的,而且对于服务器来讲,这个认识也出现了偏差。至今,没有一条确定的公式能够实现主频和实际的运算速度两者之间的数值关系,即使是两大处理器厂家Intel和AMD,在这点上也存在着很大的争议,我们从Intel的产品的发展趋势,可以看出Intel很注重加强自身主频的发展。像其他的处理器厂家,有人曾经拿过一快1G的全美达来做比较,它的运行效率相当于2G的Intel处理器。

      所以,CPU的主频与CPU实际的运算能力是没有直接关系的,主频表示在CPU内数字脉冲信号震荡的速度。在Intel的处理器产品中,我们也可以看到这样的例子:1 GHz Itanium芯片能够表现得差不多跟2.66 GHz Xeon/Opteron一样快,或是1.5 GHz Itanium 2大约跟4 GHz Xeon/Opteron一样快。CPU的运算速度还要看CPU的流水线的各方面的性能指标。

      当然,主频和实际的运算速度是有关的,只能说主频仅仅是CPU性能表现的一个方面,而不代表CPU的整体性能。   

      2.外频

      外频是CPU的基准频率,单位也是MHz。CPU的外频决定着整块主板的运行速度。说白了,在台式机中,我们所说的超频,都是超CPU的外频(当然一般情况下,CPU的倍频都是被锁住的)相信这点是很好理解的。但对于服务器CPU来讲,超频是绝对不允许的。前面说到CPU决定着主板的运行速度,两者是同步运行的,如果把服务器CPU超频了,改变了外频,会产生异步运行,(台式机很多主板都支持异步运行)这样会造成整个服务器系统的不稳定。   

      目前的绝大部分电脑系统中外频也是内存与主板之间的同步运行的速度,在这种方式下,可以理解为CPU的外频直接与内存相连通,实现两者间的同步运行状态。外频与前端总线(FSB)频率很容易被混为一谈,下面的前端总线介绍我们谈谈两者的区别。   
      3.前端总线(FSB)频率

      前端总线(FSB)频率(即总线频率)是直接影响CPU与内存直接数据交换速度。有一条公式可以计算,即数据带宽=(总线频率×数据带宽)/8,数据传输最大带宽取决于所有同时传输的数据的宽度和传输频率。比方,现在的支持64位的至强Nocona,前端总线是800MHz,按照公式,它的数据传输最大带宽是6.4GB/秒。   

      外频与前端总线(FSB)频率的区别:前端总线的速度指的是数据传输的速度,外频是CPU与主板之间同步运行的速度。也就是说,100MHz外频特指数字脉冲信号在每秒钟震荡一千万次;而100MHz前端总线指的是每秒钟CPU可接受的数据传输量是100MHz×64bit÷8Byte/bit=800MB/s。   

      其实现在“HyperTransport”构架的出现,让这种实际意义上的前端总线(FSB)频率发生了变化。之前我们知道IA-32架构必须有三大重要的构件:内存控制器Hub (MCH) ,I/O控制器Hub和PCI Hub,像Intel很典型的芯片组 Intel 7501、Intel7505芯片组,为双至强处理器量身定做的,它们所包含的MCH为CPU提供了频率为533MHz的前端总线,配合DDR内存,前端总线带宽可达到4.3GB/秒。但随着处理器性能不断提高同时给系统架构带来了很多问题。而“HyperTransport”构架不但解决了问题,而且更有效地提高了总线带宽,比方AMD Opteron处理器,灵活的HyperTransport I/O总线体系结构让它整合了内存控制器,使处理器不通过系统总线传给芯片组而直接和内存交换数据。这样的话,前端总线(FSB)频率在AMD Opteron处理器就不知道从何钙鹆恕?   

      4、CPU的位和字长

      位:在数字电路和电脑技术中采用二进制,代码只有“0”和“1”,其中无论是 “0”或是“1”在CPU中都是 一“位”。

      字长:电脑技术中对CPU在单位时间内(同一时间)能一次处理的二进制数的位数叫字长。所以能处理字长为8位数据的CPU通常就叫8位的CPU。同理32位的CPU就能在单位时间内处理字长为32位的二进制数据。字节和字长的区别:由于常用的英文字符用8位二进制就可以表示,所以通常就将8位称为一个字节。字长的长度是不固定的,对于不同的CPU、字长的长度也不一样。8位的CPU一次只能处理一个字节,而32位的CPU一次就能处理4个字节,同理字长为64位的CPU一次可以处理8个字节。   

      5.倍频系数

      倍频系数是指CPU主频与外频之间的相对比例关系。在相同的外频下,倍频越高CPU的频率也越高。但实际上,在相同外频的前提下,高倍频的CPU本身意义并不大。这是因为CPU与系统之间数据传输速度是有限的,一味追求高倍频而得到高主频的CPU就会出现明显的“瓶颈”效应—CPU从系统中得到数据的极限速度不能够满足CPU运算的速度。一般除了工程样版的Intel的CPU都是锁了倍频的,而AMD之前都没有锁。   
      6.缓存

      缓存大小也是CPU的重要指标之一,而且缓存的结构和大小对CPU速度的影响非常大,CPU内缓存的运行频率极高,一般是和处理器同频运作,工作效率远远大于系统内存和硬盘。实际工作时,CPU往往需要重复读取同样的数据块,而缓存容量的增大,可以大幅度提升CPU内部读取数据的命中率,而不用再到内存或者硬盘上寻找,以此提高系统性能。但是由于CPU芯片面积和成本的因素来考虑,缓存都很小。   

      L1 Cache(一级缓存)是CPU第一层高速缓存,分为数据缓存和指令缓存。内置的L1高速缓存的容量和结构对CPU的性能影响较大,不过高速缓冲存储器均由静态RAM组成,结构较复杂,在CPU管芯面积不能太大的情况下,L1级高速缓存的容量不可能做得太大。一般服务器CPU的L1缓存的容量通常在32—256KB。

      L2 Cache(二级缓存)是CPU的第二层高速缓存,分内部和外部两种芯片。内部的芯片二级缓存运行速度与主频相同,而外部的二级缓存则只有主频的一半。L2高速缓存容量也会影响CPU的性能,原则是越大越好,现在家庭用CPU容量最大的是512KB,而服务器和工作站上用CPU的L2高速缓存更高达256-1MB,有的高达2MB或者3MB。   

      L3 Cache(三级缓存),分为两种,早期的是外置,现在的都是内置的。而它的实际作用即是,L3缓存的应用可以进一步降低内存延迟,同时提升大数据量计算时处理器的性能。降低内存延迟和提升大数据量计算能力对游戏都很有帮助。而在服务器领域增加L3缓存在性能方面仍然有显著的提升。比方具有较大L3缓存的配置利用物理内存会更有效,故它比较慢的磁盘I/O子系统可以处理更多的数据请求。具有较大L3缓存的处理器提供更有效的文件系统缓存行为及较短消息和处理器队列长度。   

      其实最早的L3缓存被应用在AMD发布的K6-III处理器上,当时的L3缓存受限于制造工艺,并没有被集成进芯片内部,而是集成在主板上。在只能够和系统总线频率同步的L3缓存同主内存其实差不了多少。后来使用L3缓存的是英特尔为服务器市场所推出的Itanium处理器。接着就是P4EE和至强MP。Intel还打算推出一款9MB L3缓存的Itanium2处理器,和以后24MB L3缓存的双核心Itanium2处理器。   

      但基本上L3缓存对处理器的性能提高显得不是很重要,比方配备1MB L3缓存的Xeon MP处理器却仍然不是Opteron的对手,由此可见前端总线的增加,要比缓存增加带来更有效的性能提升。

      7.CPU扩展指令集

      CPU依靠指令来计算和控制系统,每款CPU在设计时就规定了一系列与其硬件电路相配合的指令系统。指令的强弱也是CPU的重要指标,指令集是提高微处理器效率的最有效工具之一。从现阶段的主流体系结构讲,指令集可分为复杂指令集和精简指令集两部分,而从具体运用看,如Intel的MMX(Multi Media Extended)、SSE、 SSE2(Streaming-Single instruction multiple data-Extensions 2)、SEE3和AMD的3DNow!等都是CPU的扩展指令集,分别增强了CPU的多媒体、图形图象和Internet等的处理能力。我们通常会把CPU的扩展指令集称为"CPU的指令集"。SSE3指令集也是目前规模最小的指令集,此前MMX包含有57条命令,SSE包含有50条命令,SSE2包含有144条命令,SSE3包含有13条命令。目前SSE3也是最先进的指令集,英特尔Prescott处理器已经支持SSE3指令集,AMD会在未来双核心处理器当中加入对SSE3指令集的支持,全美达的处理器也将支持这一指令集。  

      8.CPU内核和I/O工作电压

      从586CPU开始,CPU的工作电压分为内核电压和I/O电压两种,通常CPU的核心电压小于等于I/O电压。其中内核电压的大小是根据CPU的生产工艺而定,一般制作工艺越小,内核工作电压越低;I/O电压一般都在1.6~5V。低电压能解决耗电过大和发热过高的问题。  

      9.制造工艺

      制造工艺的微米是指IC内电路与电路之间的距离。制造工艺的趋势是向密集度愈高的方向发展。密度愈高的IC电路设计,意味着在同样大小面积的IC中,可以拥有密度更高、功能更复杂的电路设计。现在主要的180nm、130nm、90nm。最近官方已经表示有65nm的制造工艺了。

    10.指令集

      (1)CISC指令集

      CISC指令集,也称为复杂指令集,英文名是CISC,(Complex Instruction Set Computer的缩写)。在CISC微处理器中,程序的各条指令是按顺序串行执行的,每条指令中的各个操作也是按顺序串行执行的。顺序执行的优点是控制简单,但计算机各部分的利用率不高,执行速度慢。其实它是英特尔生产的x86系列(也就是IA-32架构)CPU及其兼容CPU,如AMD、VIA的。即使是现在新起的X86-64(也被成AMD64)都是属于CISC的范畴。

      要知道什么是指令集还要从当今的X86架构的CPU说起。X86指令集是Intel为其第一块16位CPU(i8086)专门开发的,IBM1981年推出的世界第一台PC机中的CPU—i8088(i8086简化版)使用的也是X86指令,同时电脑中为提高浮点数据处理能力而增加了X87芯片,以后就将X86指令集和X87指令集统称为X86指令集。

      虽然随着CPU技术的不断发展,Intel陆续研制出更新型的i80386、i80486直到过去的PII至强、PIII至强、Pentium 3,最后到今天的Pentium 4系列、至强(不包括至强Nocona),但为了保证电脑能继续运行以往开发的各类应用程序以保护和继承丰富的软件资源,所以Intel公司所生产的所有CPU仍然继续使用X86指令集,所以它的CPU仍属于X86系列。由于Intel X86系列及其兼容CPU(如AMD Athlon MP、)都使用X86指令集,所以就形成了今天庞大的X86系列及兼容CPU阵容。x86CPU目前主要有intel的服务器CPU和AMD的服务器CPU两类。

      (2)RISC指令集

      RISC是英文“Reduced Instruction Set Computing ” 的缩写,中文意思是“精简指令集”。它是在CISC指令系统基础上发展起来的,有人对CISC机进行测试表明,各种指令的使用频度相当悬殊,最常使用的是一些比较简单的指令,它们仅占指令总数的20%,但在程序中出现的频度却占80%。复杂的指令系统必然增加微处理器的复杂性,使处理器的研制时间长,成本高。并且复杂指令需要复杂的操作,必然会降低计算机的速度。基于上述原因,20世纪80年代RISC型CPU诞生了,相对于CISC型CPU ,RISC型CPU不仅精简了指令系统,还采用了一种叫做“超标量和超流水线结构”,大大增加了并行处理能力。RISC指令集是高性能CPU的发展方向。它与传统的CISC(复杂指令集)相对。相比而言,RISC的指令格式统一,种类比较少,寻址方式也比复杂指令集少。当然处理速度就提高很多了。目前在中高档服务器中普遍采用这一指令系统的CPU,特别是高档服务器全都采用RISC指令系统的CPU。RISC指令系统更加适合高档服务器的操作系统UNIX,现在Linux也属于类似UNIX的操作系统。RISC型CPU与Intel和AMD的CPU在软件和硬件上都不兼容。

      目前,在中高档服务器中采用RISC指令的CPU主要有以下几类:PowerPC处理器、SPARC处理器、PA-RISC处理器、MIPS处理器、Alpha处理器。

      (3)IA-64  

      EPIC(Explicitly Parallel Instruction Computers,精确并行指令计算机)是否是RISC和CISC体系的继承者的争论已经有很多,单以EPIC体系来说,它更像Intel的处理器迈向RISC体系的重要步骤。从理论上说,EPIC体系设计的CPU,在相同的主机配置下,处理Windows的应用软件比基于Unix下的应用软件要好得多。

      Intel采用EPIC技术的服务器CPU是安腾Itanium(开发代号即Merced)。它是64位处理器,也是IA-64系列中的第一款。微软也已开发了代号为Win64的操作系统,在软件上加以支持。在Intel采用了X86指令集之后,它又转而寻求更先进的64-bit微处理器,Intel这样做的原因是,它们想摆脱容量巨大的x86架构,从而引入精力充沛而又功能强大的指令集,于是采用EPIC指令集的IA-64架构便诞生了。IA-64 在很多方面来说,都比x86有了长足的进步。突破了传统IA32架构的许多限制,在数据的处理能力,系统的稳定性、安全性、可用性、可观理性等方面获得了突破性的提高。

      IA-64微处理器最大的缺陷是它们缺乏与x86的兼容,而Intel为了IA-64处理器能够更好地运行两个朝代的软件,它在IA-64处理器上(Itanium、Itanium2 ……)引入了x86-to-IA-64的解码器,这样就能够把x86指令翻译为IA-64指令。这个解码器并不是最有效率的解码器,也不是运行x86代码的最好途径(最好的途径是直接在x86处理器上运行x86代码),因此Itanium 和Itanium2在运行x86应用程序时候的性能非常糟糕。这也成为X86-64产生的根本原因。  

      (4)X86-64 (AMD64 / EM64T) 

      AMD公司设计,可以在同一时间内处理64位的整数运算,并兼容于X86-32架构。其中支持64位逻辑定址,同时提供转换为32位定址选项;但数据操作指令默认为32位和8位,提供转换成64位和16位的选项;支持常规用途寄存器,如果是32位运算操作,就要将结果扩展成完整的64位。这样,指令中有“直接执行”和“转换执行”的区别,其指令字段是8位或32位,可以避免字段过长。

      x86-64(也叫AMD64)的产生也并非空穴来风,x86处理器的32bit寻址空间限制在4GB内存,而IA-64的处理器又不能兼容x86。AMD充分考虑顾客的需求,加强x86指令集的功能,使这套指令集可同时支持64位的运算模式,因此AMD把它们的结构称之为x86-64。在技术上AMD在x86-64架构中为了进行64位运算,AMD为其引入了新增了R8-R15通用寄存器作为原有X86处理器寄存器的扩充,但在而在32位环境下并不完全使用到这些寄存器。原来的寄存器诸如EAX、EBX也由32位扩张至64位。在SSE单元中新加入了8个新寄存器以提供对SSE2的支持。寄存器数量的增加将带来性能的提升。与此同时,为了同时支持32和64位代码及寄存器,x86-64架构允许处理器工作在以下两种模式:Long Mode(长模式)和Legacy Mode(遗传模式),Long模式又分为两种子模式(64bit模式和Compatibility mode兼容模式)。该标准已经被引进在AMD服务器处理器中的Opteron处理器。

      而今年也推出了支持64位的EM64T技术,再还没被正式命为EM64T之前是IA32E,这是英特尔64位扩展技术的名字,用来区别X86指令集。Intel的EM64T支持64位sub-mode,和AMD的X86-64技术类似,采用64位的线性平面寻址,加入8个新的通用寄存器(GPRs),还增加8个寄存器支持SSE指令。与AMD相类似,Intel的64位技术将兼容IA32和IA32E,只有在运行64位操作系统下的时候,才将会采用IA32E。IA32E将由2个sub-mode组成:64位sub-mode和32位sub-mode,同AMD64一样是向下兼容的。Intel的EM64T将完全兼容AMD的X86-64技术。现在Nocona处理器已经加入了一些64位技术,Intel的Pentium 4E处理器也支持64位技术。  

      应该说,这两者都是兼容x86指令集的64位微处理器架构,但EM64T与AMD64还是有一些不一样的地方,AMD64处理器中的NX位在Intel的处理器中将没有提供。

      11.超流水线与超标量

      在解释超流水线与超标量前,先了解流水线(pipeline)。流水线是Intel首次在486芯片中开始使用的。流水线的工作方式就象工业生产上的装配流水线。在CPU中由5—6个不同功能的电路单元组成一条指令处理流水线,然后将一条X86指令分成5—6步后再由这些电路单元分别执行,这样就能实现在一个CPU时钟周期完成一条指令,因此提高CPU的运算速度。经典奔腾每条整数流水线都分为四级流水,即指令预取、译码、执行、写回结果,浮点流水又分为八级流水。

      超标量是通过内置多条流水线来同时执行多个处理器,其实质是以空间换取时间。而超流水线是通过细化流水、提高主频,使得在一个机器周期内完成一个甚至多个操作,其实质是以时间换取空间。例如Pentium 4的流水线就长达20级。将流水线设计的步(级)越长,其完成一条指令的速度越快,因此才能适应工作主频更高的CPU。但是流水线过长也带来了一定副作用,很可能会出现主频较高的CPU实际运算速度较低的现象,Intel的奔腾4就出现了这种情况,虽然它的主频可以高达1.4G以上,但其运算性能却远远比不上AMD 1.2G的速龙甚至奔腾III。

      12.封装形式

      CPU封装是采用特定的材料将CPU芯片或CPU模块固化在其中以防损坏的保护措施,一般必须在封装后CPU才能交付用户使用。CPU的封装方式取决于CPU安装形式和器件集成设计,从大的分类来看通常采用Socket插座进行安装的CPU使用PGA(栅格阵列)方式封装,而采用Slot x槽安装的CPU则全部采用SEC(单边接插盒)的形式封装。现在还有PLGA(Plastic Land Grid Array)、OLGA(Organic Land Grid Array)等封装技术。由于市场竞争日益激烈,目前CPU封装技术的发展方向以节约成本为主。

      13、多线程   

      同时多线程Simultaneous multithreading,简称SMT。SMT可通过复制处理器上的结构状态,让同一个处理器上的多个线程同步执行并共享处理器的执行资源,可最大限度地实现宽发射、乱序的超标量处理,提高处理器运算部件的利用率,缓和由于数据相关或Cache未命中带来的访问内存延时。当没有多个线程可用时,SMT处理器几乎和传统的宽发射超标量处理器一样。SMT最具吸引力的是只需小规模改变处理器核心的设计,几乎不用增加额外的成本就可以显著地提升效能。多线程技术则可以为高速的运算核心准备更多的待处理数据,减少运算核心的闲置时间。这对于桌面低端系统来说无疑十分具有吸引力。Intel从3.06GHz Pentium 4开始,所有处理器都将支持SMT技术。

      14、多核心

      多核心,也指单芯片多处理器(Chip multiprocessors,简称CMP)。CMP是由美国斯坦福大学提出的,其思想是将大规模并行处理器中的SMP(对称多处理器)集成到同一芯片内,各个处理器并行执行不同的进程。与CMP比较, SMT处理器结构的灵活性比较突出。但是,当半导体工艺进入0.18微米以后,线延时已经超过了门延迟,要求微处理器的设计通过划分许多规模更小、局部性更好的基本单元结构来进行。相比之下,由于CMP结构已经被划分成多个处理器核来设计,每个核都比较简单,有利于优化设计,因此更有发展前途。目前,IBM 的Power 4芯片和Sun的 MAJC5200芯片都采用了CMP结构。多核处理器可以在处理器内部共享缓存,提高缓存利用率,同时简化多处理器系统设计的复杂度。

      2005年下半年,Intel和AMD的新型处理器也将融入CMP结构。新安腾处理器开发代码为Montecito,采用双核心设计,拥有最少18MB片内缓存,采取90nm工艺制造,它的设计绝对称得上是对当今芯片业的挑战。它的每个单独的核心都拥有独立的L1,L2和L3 cache,包含大约10亿支晶体管。

      15、SMP

      SMP(Symmetric Multi-Processing),对称多处理结构的简称,是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构。在这种技术的支持下,一个服务器系统可以同时运行多个处理器,并共享内存和其他的主机资源。像双至强,也就是我们所说的二路,这是在对称处理器系统中最常见的一种(至强MP可以支持到四路,AMD Opteron可以支持1-8路)。也有少数是16路的。但是一般来讲,SMP结构的机器可扩展性较差,很难做到100个以上多处理器,常规的一般是8个到16个,不过这对于多数的用户来说已经够用了。在高性能服务器和工作站级主板架构中最为常见,像UNIX服务器可支持最多256个CPU的系统。

      构建一套SMP系统的必要条件是:支持SMP的硬件包括主板和CPU;支持SMP的系统平台,再就是支持SMP的应用软件。

      为了能够使得SMP系统发挥高效的性能,操作系统必须支持SMP系统,如WINNT、LINUX、以及UNIX等等32位操作系统。即能够进行多任务和多线程处理。多任务是指操作系统能够在同一时间让不同的CPU完成不同的任务;多线程是指操作系统能够使得不同的CPU并行的完成同一个任务。

      要组建SMP系统,对所选的CPU有很高的要求,首先、CPU内部必须内置APIC(Advanced Programmable Interrupt Controllers)单元。Intel 多处理规范的核心就是高级可编程中断控制器(Advanced Programmable Interrupt Controllers--APICs)的使用;再次,相同的产品型号,同样类型的CPU核心,完全相同的运行频率;最后,尽可能保持相同的产品序列编号,因为两个生产批次的CPU作为双处理器运行的时候,有可能会发生一颗CPU负担过高,而另一颗负担很少的情况,无法发挥最大性能,更糟糕的是可能导致死机。

      16、NUMA技术

      NUMA即非一致访问分布共享存储技术,它是由若干通过高速专用网络连接起来的独立节点构成的系统,各个节点可以是单个的CPU或是SMP系统。在NUMA中,Cache 的一致性有多种解决方案,需要操作系统和特殊软件的支持。图2中是Sequent公司NUMA系统的例子。这里有3个SMP模块用高速专用网络联起来,组成一个节点,每个节点可以有12个CPU。像Sequent的系统最多可以达到64个CPU甚至256个CPU。显然,这是在SMP的基础上,再用NUMA的技术加以扩展,是这两种技术的结合。

      

      17、乱序执行技术

      乱序执行(out-of-orderexecution),是指CPU允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。这样将根据个电路单元的状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路单元执行,在这期间不按规定顺序执行指令,然后由重新排列单元将各执行单元结果按指令顺序重新排列。采用乱序执行技术的目的是为了使CPU内部电路满负荷运转并相应提高了CPU的运行程序的速度。分枝技术:(branch)指令进行运算时需要等待结果,一般无条件分枝只需要按指令顺序执行,而条件分枝必须根据处理后的结果,再决定是否按原先顺序进行。

      18、CPU内部的内存控制器

      许多应用程序拥有更为复杂的读取模式(几乎是随机地,特别是当cache hit不可预测的时候),并且没有有效地利用带宽。典型的这类应用程序就是业务处理软件,即使拥有如乱序执行(out of order execution)这样的CPU特性,也会受内存延迟的限制。这样CPU必须得等到运算所需数据被除数装载完成才能执行指令(无论这些数据来自CPU cache还是主内存系统)。当前低段系统的内存延迟大约是120-150ns,而CPU速度则达到了3GHz以上,一次单独的内存请求可能会浪费200-300次CPU循环。即使在缓存命中率(cache hit rate)达到99%的情况下,CPU也可能会花50%的时间来等待内存请求的结束- 比如因为内存延迟的缘故。

      你可以看到Opteron整合的内存控制器,它的延迟,与芯片组支持双通道DDR内存控制器的延迟相比来说,是要低很多的。英特尔也按照计划的那样在处理器内部整合内存控制器,这样导致北桥芯片将变得不那么重要。但改变了处理器访问主存的方式,有助于提高带宽、降低内存延时和提升处理器性能

    November 28

    js的url编码问题(转自无忧脚本-小虫)

    编码转换一般用在Microsoft.XMLHTTP传递客户端提交内容
    或者XMLdoc .load(xxx.aspx?带有汉字的参数需要转换)
    代码测试中,到现在一直运行正常,测试环境Ie5.00 ,Ie6.0
    <script language="vbscript">
    Function vbChar(thischr)
    innercode = asc(thischr)
    If innercode < 0 Then innercode = innercode + &h10000
    vbChar=innercode
    End Function
    </script>
    <script language="javascript">
    //unicode 转换成Url-gb2312编码
    alert(urlencoding("中"));
    function urlencoding(szInput)
    {
    var wch,x,uch="",szRet="";
    var strSpecial = "#$%'()*+,/:;<=>?@[\\]^`{|}~%";
    //转换特殊的字符&没有包含在里面因为是参数连接符号
     for (x=0; x<szInput.length; x++){
      wch=vbChar(szInput.charAt(x));
        if (!(wch & 0xFF80)){
          if (szRet==32)szRet +="+";
          else if(strSpecial.indexOf(szInput.charAt(x))>=0)
                   szRet += "%" + wch.toString(16);
          else szRet += szInput.charAt(x);
        }
        else{
          uch = "%" + (wch>>8 ).toString(16) +
            "%" + (wch & 0xFF).toString(16);
          szRet += uch;
        }
     }
      return(szRet);
    }
    </script>
     
     
     
     
     
    将输入串中的汉字变为UniCode(UTF8),其它字符不变
    <script>
    alert(toUTF8("中"));
    function toUTF8(szInput){
     var wch,x,uch="",szRet="";
     for (x=0; x<szInput.length; x++){
      wch=szInput.charCodeAt(x);
      if (!(wch & 0xFF80)){
       szRet += szInput.charAt(x);
      }
      else if (!(wch & 0xF000)){
       uch = "%" + (wch>>6 | 0xC0).toString(16) +
          "%" + (wch & 0x3F | 0x80).toString(16);
       szRet += uch;
      }
      else{
       uch = "%" + (wch >> 12 | 0xE0).toString(16) +
          "%" + (((wch >> 6) & 0x3F) | 0x80).toString(16) +
          "%" + (wch & 0x3F | 0x80).toString(16);
       szRet += uch;
      }
     }
     return(szRet);
    }
    </script>
    November 25

    js得到客户端MAC

     
    寻觅了一段时间,终于找到这段代码了。
    不过还是要调用activeX,在非win的操作系统上还没有测试过。非ie浏览器也没测试过。
    不过毕竟还有一个能凑合用着。
     
    ^_^
     
    代码如下:
     
    <SCRIPT language=JScript event="OnCompleted(hResult,pErrorObject, pAsyncContext)" for="foo">
    document.write (unescape(MACAddr));
    </SCRIPT>
    <SCRIPT language=JScript event="OnObjectReady(objObject,objAsyncContext)" for="foo">
    if(objObject.IPEnabled != null && objObject.IPEnabled != "undefined" && objObject.IPEnabled == true && objObject.MACAddress != null && objObject.MACAddress != "undefined")MACAddr = objObject.MACAddress;
    </SCRIPT>
    <OBJECT id="locator" classid="CLSID:76A64158-CB41-11D1-8B02-00600806D9B6 VIEWASTEXT"></OBJECT>
    <OBJECT id="foo" classid="CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223"></OBJECT>
    <SCRIPT language=JScript>
    var service = locator.ConnectServer();
    var MACAddr ;
    var IPAddr ;
    var DomainAddr;
    var sDNSName;
    service.Security_.ImpersonationLevel=3;
    service.InstancesOfAsync(foo, 'Win32_NetworkAdapterConfiguration');
    </SCRIPT>
    November 20

    传说中的AJAX技术在php中的应用

    以下是ajax在php中的一个实例,任何其他页面脚本用法也相同。
    程序很简单,这里就不多做解释了。
    前端页面,既始终显示给用户的页面:
    <script type="text/javascript" language="javascript">
    var http_request = false;
    function makeRequest(url) {
        http_request = false;
        if (window.XMLHttpRequest) { // 非ie浏览器
            http_request = new XMLHttpRequest();
            if (http_request.overrideMimeType) {
                http_request.overrideMimeType('text/xml');
            }
        } else if (window.ActiveXObject) { // ie浏览器
            try {
                http_request = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    http_request = new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e) {}
            }
        }
        if (!http_request) {
            alert('Giving up :( Cannot create an XMLHTTP instance');
            return false;
        }
        http_request.onreadystatechange = alertContents;
        http_request.open('GET', url, true);
        http_request.send(null);
    }
    function alertContents() {
        if (http_request.readyState == 4) {
            if (http_request.status == 200) {
              content.innerHTML=http_request.responseText;
            } else {
                alert('There was a problem with the request.');
            }
        }
    }
    </script>
    <form name="frmLogin" action="" method="get">
    name:<input type="text" name="name"><br>
    password:<input type="password" name="password"><br>
    <input type="button" value="ok" onclick="makeRequest('a.php?name='+frmLogin.name.value+'&password='+frmLogin.password.value);">
    </form>
    <div id="content">
    </div>
    后端页面,也就是上页中所调用的a.php
    <?
    echo $_GET["name"].$_GET["password"];
    ?>
    通过http调用前端页面后显示name和password输入框。
    输入字符点击ok按钮以后在content层中显示出之前输入的用户名和密码。
    而所显示的用户名和密码是通过get方式传递给后端页面,由后端页面打印出来的。
    可以通过把上面xmlsocket的方法封装后作为一种普遍的页面级socket调用来使用。
    可以把它加在任何想要实现ajax功能的页面元素或者标签上。
     
    在此还想到,一般的表单输入域验证可以通过这样的调用省去前端的js验证部分代码,验证规则可以统一使用动态脚本语言写成的验证类。
    November 17

    sqlplus命令大全

     

    摘录,非本人原创

     
    1. 执行一个SQL脚本文件
    SQL>start file_name
    SQL>@ file_name
    我们可以将多条sql语句保存在一个文本文件中,这样当要执行这个文件中的所有的sql语句时,用上面的任一命令即可,这类似于dos中的批处理。
     
    2. 对当前的输入进行编辑
    SQL>edit
     
    3. 重新运行上一次运行的sql语句
    SQL>/
     
    4. 将显示的内容输出到指定文件
    SQL> SPOOL file_name
       在屏幕上的所有内容都包含在该文件中,包括你输入的sql语句。
     
    5. 关闭spool输出
    SQL> SPOOL OFF
       只有关闭spool输出,才会在输出文件中看到输出的内容。
     


    6.显示一个表的结构
    SQL> desc table_name
     
    7. COL命令:
    主要格式化列的显示形式。
    该命令有许多选项,具体如下:
    COL[UMN] [{ column|expr} [ option ...]]
    Option选项可以是如下的子句:
    ALI[AS] alias
    CLE[AR]
    FOLD_A[FTER]
    FOLD_B[EFORE]
    FOR[MAT] format
    HEA[DING] text
    JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}
    LIKE { expr|alias}
    NEWL[INE]
    NEW_V[ALUE] variable
    NOPRI[NT]|PRI[NT]
    NUL[L] text
    OLD_V[ALUE] variable
    ON|OFF
    WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]
     
    1). 改变缺省的列标题
    COLUMN column_name HEADING column_heading
    For example:
    Sql>select * from dept;
         DEPTNO DNAME                        LOC
    ---------- ---------------------------- ---------
             10 ACCOUNTING                   NEW YORK
    sql>col  LOC heading location
    sql>select * from dept;
        DEPTNO DNAME                        location
    --------- ---------------------------- -----------
            10 ACCOUNTING                   NEW YORK
     
    2). 将列名ENAME改为新列名EMPLOYEE NAME并将新列名放在两行上:
    Sql>select * from emp
    Department  name           Salary
    ---------- ---------- ----------
             10 aaa                11        
    SQL> COLUMN ENAME HEADING ’Employee|Name’
    Sql>select * from emp
                Employee
    Department  name           Salary
    ---------- ---------- ---------- 
             10 aaa                11
    note: the col heading turn into two lines from one line.
     
    3). 改变列的显示长度:
    FOR[MAT] format
    Sql>select empno,ename,job from emp;
          EMPNO ENAME      JOB       
    ---------- ----------     ---------
           7369 SMITH      CLERK     
           7499 ALLEN      SALESMAN  
    7521 WARD       SALESMAN  
    Sql> col ename format a40
          EMPNO ENAME                                    JOB
    ----------   ----------------------------------------         ---------
           7369 SMITH                                    CLERK
           7499 ALLEN                                    SALESMAN
           7521 WARD                                    SALESMAN
     
    4). 设置列标题的对齐方式
    JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}
    SQL> col ename justify center
    SQL> /
          EMPNO           ENAME                   JOB
    ----------   ----------------------------------------       ---------
           7369 SMITH                                    CLERK
           7499 ALLEN                                    SALESMAN
    7521 WARD                                     SALESMAN
    对于NUMBER型的列,列标题缺省在右边,其它类型的列标题缺省在左边
     
    5). 不让一个列显示在屏幕上
    NOPRI[NT]|PRI[NT]
    SQL> col job noprint
    SQL> /
          EMPNO           ENAME
    ----------     ----------------------------------------
           7369 SMITH
           7499 ALLEN
    7521 WARD
     
    6). 格式化NUMBER类型列的显示:
    SQL> COLUMN SAL FORMAT $99,990
    SQL> /
    Employee
    Department Name        Salary    Commission
    ---------- ---------- --------- ----------
    30          ALLEN        $1,600    300
     
    7). 显示列值时,如果列值为NULL值,用text值代替NULL值
    COMM NUL[L] text
    SQL>COL COMM NUL[L] text
     
    8). 设置一个列的回绕方式
    WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]
            COL1
    --------------------
    HOW ARE YOU?
     
    SQL>COL COL1 FORMAT A5
    SQL>COL COL1 WRAPPED
    COL1
    -----
    HOW A
    RE YO
    U?
     
    SQL> COL COL1 WORD_WRAPPED
    COL1
    -----
    HOW
    ARE
    YOU?
     
    SQL> COL COL1 WORD_WRAPPED
    COL1
    -----
    HOW A
     
    9). 显示列的当前的显示属性值
    SQL> COLUMN column_name
     
    10). 将所有列的显示属性设为缺省值
    SQL> CLEAR COLUMNS
     
    8. 屏蔽掉一个列中显示的相同的值
    BREAK ON break_column
    SQL> BREAK ON DEPTNO
    SQL> SELECT DEPTNO, ENAME, SAL
    FROM EMP
      WHERE SAL < 2500
      ORDER BY DEPTNO;
    DEPTNO      ENAME         SAL
    ---------- ----------- ---------
    10           CLARK        2450
    MILLER      1300
    20            SMITH       800
    ADAMS       1100
     
    9. 在上面屏蔽掉一个列中显示的相同的值的显示中,每当列值变化时在值变化之前插入n个空行。
    BREAK ON break_column SKIP n
     
    SQL> BREAK ON DEPTNO SKIP 1
    SQL> /
    DEPTNO ENAME SAL
    ---------- ----------- ---------
    10 CLARK 2450
    MILLER 1300
     
    20 SMITH 800
    ADAMS 1100
     
    10. 显示对BREAK的设置
    SQL> BREAK
     
    11. 删除6、7的设置
    SQL> CLEAR BREAKS
     
    12. Set 命令:
    该命令包含许多子命令:
    SET system_variable value
    system_variable value 可以是如下的子句之一:
    APPI[NFO]{ON|OFF|text}
    ARRAY[SIZE] {15|n}
    AUTO[COMMIT]{ON|OFF|IMM[EDIATE]|n}
    AUTOP[RINT] {ON|OFF}
    AUTORECOVERY [ON|OFF]
    AUTOT[RACE] {ON|OFF|TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
    BLO[CKTERMINATOR] {.|c}
    CMDS[EP] {;|c|ON|OFF}
    COLSEP {_|text}
    COM[PATIBILITY]{V7|V8|NATIVE}
    CON[CAT] {.|c|ON|OFF}
    COPYC[OMMIT] {0|n}
    COPYTYPECHECK {ON|OFF}
    DEF[INE] {&|c|ON|OFF}
    DESCRIBE [DEPTH {1|n|ALL}][LINENUM {ON|OFF}][INDENT {ON|OFF}]
    ECHO {ON|OFF}
    EDITF[ILE] file_name[.ext]
    EMB[EDDED] {ON|OFF}
    ESC[APE] {|c|ON|OFF}
    FEED[BACK] {6|n|ON|OFF}
    FLAGGER {OFF|ENTRY |INTERMED[IATE]|FULL}
    FLU[SH] {ON|OFF}
    HEA[DING] {ON|OFF}
    HEADS[EP] {||c|ON|OFF}
    INSTANCE [instance_path|LOCAL]
    LIN[ESIZE] {80|n}
    LOBOF[FSET] {n|1}
    LOGSOURCE [pathname]
    LONG {80|n}
    LONGC[HUNKSIZE] {80|n}
    MARK[UP] HTML [ON|OFF] [HEAD text] [BODY text] [ENTMAP {ON|OFF}] [SPOOL
    {ON|OFF}] [PRE[FORMAT] {ON|OFF}]
    NEWP[AGE] {1|n|NONE}
    NULL text
    NUMF[ORMAT] format
    NUM[WIDTH] {10|n}
    PAGES[IZE] {24|n}
    PAU[SE] {ON|OFF|text}
    RECSEP {WR[APPED]|EA[CH]|OFF}
    RECSEPCHAR {_|c}
    SERVEROUT[PUT] {ON|OFF} [SIZE n] [FOR[MAT] {WRA[PPED]|WOR[D_
    WRAPPED]|TRU[NCATED]}]
    SHIFT[INOUT] {VIS[IBLE]|INV[ISIBLE]}
    SHOW[MODE] {ON|OFF}
    SQLBL[ANKLINES] {ON|OFF}
    SQLC[ASE] {MIX[ED]|LO[WER]|UP[PER]}
    SQLCO[NTINUE] {> |text}
    SQLN[UMBER] {ON|OFF}
    SQLPRE[FIX] {#|c}
    SQLP[ROMPT] {SQL>|text}
    SQLT[ERMINATOR] {;|c|ON|OFF}
    SUF[FIX] {SQL|text}
    TAB {ON|OFF}
    TERM[OUT] {ON|OFF}
    TI[ME] {ON|OFF}
    TIMI[NG] {ON|OFF}
    TRIM[OUT] {ON|OFF}
    TRIMS[POOL] {ON|OFF}
    UND[ERLINE] {-|c|ON|OFF}
    VER[IFY] {ON|OFF}
    WRA[P] {ON|OFF}
     
    1). 设置当前session是否对修改的数据进行自动提交
    SQL>SET AUTO[COMMIT] {ON|OFF|IMM[EDIATE]| n}
     
    2).在用start命令执行一个sql脚本时,是否显示脚本中正在执行的SQL语句
    SQL> SET ECHO {ON|OFF}
     
    3).是否显示当前sql语句查询或修改的行数
    SQL> SET FEED[BACK] {6|n|ON|OFF}
       默认只有结果大于6行时才显示结果的行数。如果set feedback 1 ,则不管查询到多少行都返回。当为off 时,一律不显示查询的行数
     
    4).是否显示列标题
    SQL> SET HEA[DING] {ON|OFF}
    当set heading off 时,在每页的上面不显示列标题,而是以空白行代替
     
    5).设置一行可以容纳的字符数
    SQL> SET LIN[ESIZE] {80|n}
       如果一行的输出内容大于设置的一行可容纳的字符数,则折行显示。
     
    6).设置页与页之间的分隔
    SQL> SET NEWP[AGE] {1|n|NONE}
    当set newpage 0 时,会在每页的开头有一个小的黑方框。
    当set newpage n 时,会在页和页之间隔着n个空行。
    当set newpage none 时,会在页和页之间没有任何间隔。
     
    7).显示时,用text值代替NULL值
    SQL> SET NULL text
     
    8).设置一页有多少行数
    SQL> SET PAGES[IZE] {24|n}
    如果设为0,则所有的输出内容为一页并且不显示列标题
     
    9).是否显示用DBMS_OUTPUT.PUT_LINE包进行输出的信息。
    SQL> SET SERVEROUT[PUT] {ON|OFF} 
    在编写存储过程时,我们有时会用dbms_output.put_line将必要的信息输出,以便对存储过程进行调试,只有将serveroutput变量设为on后,信息才能显示在屏幕上。
     
    10).当SQL语句的长度大于LINESIZE时,是否在显示时截取SQL语句。
    SQL> SET WRA[P] {ON|OFF}
       当输出的行的长度大于设置的行的长度时(用set linesize n命令设置),当set wrap on时,输出行的多于的字符会另起一行显示,否则,会将输出行的多于字符切除,不予显示。
     
    11).是否在屏幕上显示输出的内容,主要用与SPOOL结合使用。
    SQL> SET TERM[OUT] {ON|OFF}
       在用spool命令将一个大表中的内容输出到一个文件中时,将内容输出在屏幕上会耗费大量的时间,设置set termspool off后,则输出的内容只会保存在输出文件中,不会显示在屏幕上,极大的提高了spool的速度。
     
    12).将SPOOL输出中每行后面多余的空格去掉
    SQL> SET TRIMS[OUT] {ON|OFF} 
       
    13)显示每个sql语句花费的执行时间
    set TIMING  {ON|OFF}
     
    14.修改sql buffer中的当前行中,第一个出现的字符串
    C[HANGE] /old_value/new_value
    SQL> l
       1* select * from dept
    SQL> c/dept/emp
       1* select * from emp
     
    15.编辑sql buffer中的sql语句
    EDI[T]
     
    16.显示sql buffer中的sql语句,list n显示sql buffer中的第n行,并使第n行成为当前行
    L[IST] [n]
     
    17.在sql buffer的当前行下面加一行或多行
    I[NPUT]
     
    18.将指定的文本加到sql buffer的当前行后面
    A[PPEND]
    SQL> select deptno,
       2  dname
       3  from dept;
         DEPTNO DNAME
    ---------- --------------
             10 ACCOUNTING
             20 RESEARCH
             30 SALES
             40 OPERATIONS
     
    SQL> L 2
       2* dname
    SQL> a ,loc
       2* dname,loc
    SQL> L
       1  select deptno,
       2  dname,loc
       3* from dept
    SQL> /
     
         DEPTNO DNAME          LOC
    ---------- -------------- -------------
             10 ACCOUNTING     NEW YORK
             20 RESEARCH       DALLAS
             30 SALES          CHICAGO
             40 OPERATIONS     BOSTON
     
    19.将sql buffer中的sql语句保存到一个文件中
    SAVE file_name
     
    20.将一个文件中的sql语句导入到sql buffer中
    GET file_name
     
    21.再次执行刚才已经执行的sql语句
    RUN
    or
    /
     
    22.执行一个存储过程
    EXECUTE procedure_name
     
    23.在sql*plus中连接到指定的数据库
    CONNECT user_name/passwd@db_alias
     
    24.设置每个报表的顶部标题
    TTITLE
     
    25.设置每个报表的尾部标题
    BTITLE
     
    26.写一个注释
    REMARK [text]
     
    27.将指定的信息或一个空行输出到屏幕上
    PROMPT [text]
     
    28.将执行的过程暂停,等待用户响应后继续执行
    PAUSE [text]
     
    Sql>PAUSE Adjust paper and press RETURN to continue.
     
    29.将一个数据库中的一些数据拷贝到另外一个数据库(如将一个表的数据拷贝到另一个数据库)
    COPY {FROM database | TO database | FROM database TO database}
    {APPEND|CREATE|INSERT|REPLACE} destination_table
    [(column, column, column, ...)] USING query
     
    sql>COPY FROM SCOTT/TIGER@HQ TO JOHN/CHROME@WEST 
    create emp_temp
    USING SELECT * FROM EMP
     
    30.不退出sql*plus,在sql*plus中执行一个操作系统命令:
    HOST
     
    Sql> host hostname
    该命令在windows下可能被支持。
     
    31.在sql*plus中,切换到操作系统命令提示符下,运行操作系统命令后,可以再次切换回sql*plus:
    !
     
    sql>!
    $hostname
    $exit
    sql>
     
    该命令在windows下不被支持。
     
    32.显示sql*plus命令的帮助
    HELP
    如何安装帮助文件:
    Sql>@ ?sqlplusadminhelphlpbld.sql ?sqlplusadminhelphelpus.sql
    Sql>help index
     
    33.显示sql*plus系统变量的值或sql*plus环境变量的值
    Syntax
    SHO[W] option
    where option represents one of the following terms or clauses:
    system_variable
    ALL
    BTI[TLE]
    ERR[ORS] [{FUNCTION|PROCEDURE|PACKAGE|PACKAGE BODY|
    TRIGGER|VIEW|TYPE|TYPE BODY} [schema.]name]
    LNO
    PARAMETERS [parameter_name]
    PNO
    REL[EASE]
    REPF[OOTER]
    REPH[EADER]
    SGA
    SPOO[L]
    SQLCODE
    TTI[TLE]
    USER
     
    1) . 显示当前环境变量的值:
    Show all
     
    2) . 显示当前在创建函数、存储过程、触发器、包等对象的错误信息
    Show error
    当创建一个函数、存储过程等出错时,变可以用该命令查看在那个地方出错及相应的出错信息,进行修改后再次进行编译。
     
    3) . 显示初始化参数的值:
    show PARAMETERS [parameter_name]
     
    4) . 显示数据库的版本:
    show REL[EASE]
     
    5) . 显示SGA的大小
    show SGA
     
    6). 显示当前的用户名
    show user