共 170篇 前 10 页: 10    每页10篇 下一页  

自荐文章

〖摘要:〗

solr默认的分词是按照单词来分的,中文则是按照每个汉字。例如“中国人自强不息”会分为“中”、“国”、“人”、“自”……,这样的分词效果并不理想。

中文分词目前知道“庖丁就牛”这个分词程序比较有名,按照说明文档安装后一直出现“java.lang.AbstractMethodError: org.apache.lucene.analysis.TokenStream.incrementToken()Z",初步判断是版本不兼容的问题,“庖丁解牛”没有发布对应lucene3.5的版本。据说paoding官方源代码是支持的,遂 svn co http://paoding.googlecode.com/svn/trunk/paoding-analysis/,然后 ant build了一份,果然成功了。

简单讲一下配置部署

一、首先部署 solr

昨天文章中讲了如何在Tomcat中部署 solr,这里不重复。

二、下载并配置paoding

上面讲了默认发布的paoding-analysis-2.0.4.jar不兼容lucene-3.5.0,需要按照上面的方法下载源代码,在执行完ant build后能得到 paoding-analysis.jar。

中文分词是依赖词库的,paoding官方提供了一套词库,基本够用,也就是和 src目录在一起的 dic 目录,这个目录在solr运行的时候需要在 $CLASSPATH中。

三、重新打包 solr.war

使用解压工具打开 solr.war,将 paoding-analysis.jar 放在 solr/WEB-INF/lib/下,由于 dic (字典)目录需要在 classpath中,我的做法是直接将其复制到 solr/WEB-INF/classes 目录下,然后打包成新的 solr.war并发布。到这里已经可以重新启动 solr服务了,但还缺少将默认的分词器修改成paoding。

四、配置paoding分词器

昨天文章中提到需要配置 solr/home这个目录,进入这个目录打开 conf/schema.xml。这里就是配置lucene建立索引的字段。这里以测试“subject”字段为例,subject字段的类型是“text_general”,text_general使用的是默认的分词器,修改为使用paoding分词器:

<fieldType name="text_general" class="solr.TextField">
  <analyzer type="index" class="net.paoding.analysis.analyzer.PaodingAnalyzer"  positionIncrementGap="100">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
    <!-- in this example, we will only use synonyms at query time
    <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
    -->
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
  <analyzer type="query" class="net.paoding.analysis.analyzer.PaodingAnalyzer" positionIncrementGap="100">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
    <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>
上面标红的部分是添加的内容。然后重启solr服务。

五、测试

从控制台中直接测试分词效果:http://localhost:8080/solr/admin/analysis.jsp?highlight=on

name: subject 、 Field value: 中华人名共和国 -> 分词结果: 中华、华人、人名、共和、共和国

导入一条数据测试:

~$: vi cn_title.xml

<add>
<doc>
  <field name="id">test0003</field>
  <field name="subject">首先:我为您推荐的这套房子是亦庄里单价最低,户型最好,不临街,性价比最高的一套房屋,如果您想在亦庄置业的话,别再犹豫了,相信自己,相信鑫尊</field>
</doc>
</add>
~$: java -Durl=http://localhost:8080/solr/update -jar post.jar cn_title.xml

成功后在solr控制台中搜索:subject:首先 ,并且带上 url 参数:&facet.field=subject&facet=true,查看分词及搜索结果:
<response>
meiking   2012-02-17 15:23:29 阅读:565  评论:0  引用:0

最近一段时间有空,准备学习一下lucene。

学习目标

  1. 使用起来,包括安装、配置、solr及爬虫的安装
  2. 充分了解其功能特性,包括:中文分词索引、中文分词搜索、结果评分等
  3. 弄清出其软件架构
  4. 进阶目标:
    • 架设分布式solr运行环境
    • 扩展其索引方式为分布式索引

首先下载软件包: 可以用人人网的源:http://labs.renren.com/apache-mirror//lucene/solr/,我选择的是3.5.0。

安装: 解压 apache-solr-3.5.0.tgz 后进入 example 后可以选择使用 webapps/ 下的 solr.war 在标准的j2ee servlet容器中启动,或者 java -jar start.jar,然后在浏览器中输入 http://localhost:8983/solr/admin/,看到正常的“Solr Admin (example)”页面就表示启动成功。

测试搜索: 默认的启动界面中搜索内容为 “*:*”,表示匹配所有字段,并且匹配任意内容,相当于 select * from [table] where 1 = 1。不过这个时候索引库里还没有任何内容,所以搜索不出任何东西。这里可以看一下默认solr中的一套数据结构,点击“SCHEMA BROWSER”可以看到索引的字段以及索引的一个简单统计情况。

测试索引: 进入 example/exampledocs/目录,运行: java -jar post.jar monitor.xml solr.xml。运行成功后回到solr控制台,在搜索输入框中输入“cat:software”,当结果有变化时表示索引建立成功。再回头看看 solr.xml 的内容,可以发现solr.xml的内容的格式就是刚刚在 "SCHEMA BROWSER"中看到的。solr支持的搜索表达式很丰富,可以从这里找到其支持的所有表达式:http://wiki.apache.org/solr/SolrQuerySyntax。
使用java -jar post.jar --help命令可以看到其支持的导入索引格式还有 csv、json、pdf。另外此目录下还有个post.sh命令,比较简单,支持直接 post xml格式的文件。简单测试了一下中文问题,目前没发现什么问题。

删除索引: 命令行模式支持 java -Ddata=args -jar post.jar "<delete><id>3007WFP</id></delete>"

其它搜索参数:
自定义返回字段:搜索结果url上加上“fl=name,id”(返回name,id)
定义返回格式为JSON:wt=json
结果排序:sort=price desc 、 sort=inStock asc, price desc,目前还没有测试中文排序
高亮搜索关键字:hl.fl=name,features(高亮现实 name和features两个字段中的搜索关键字,默认使用<em>)
统计索引库中包含的搜索关键字:facet.field=cat&facet=true

Tomcat中部署solr: 首先修改$TOMECAT_HOME/conf/server.xml:添加 URIEncoding<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>,再创建文件:$TOMCAT_HOME/conf/Catalina/localhost/solr.xml,内容:<Context docBase="/home/meiking/opt/apache-solr-3.5.0/example/webapps/solr.war" reloadable="true" > <Environment name="solr/home" type="java.lang.String" value="/home/meiking/opt/apache-solr-3.5.0/example/solr" override="true" /> </Context> ,将上面标红的部分替换为自己的内容。

结论:solr基于lucene开发,将lucene java 借口封装成通用webservice接口,solr支持的语法规则很丰富。

meiking   2012-02-16 18:10:01 阅读:285  评论:0  引用:0

最近开始学习Objective-C,由于是C语言的扩展,且完全兼容C的语法,基本上可以认为是面向对象的C。C一直没有真正实际用过,学习的时候也没有深去研究,由其是指针这一块,一直一知半解。

这里复习一下概念上的理解,等以后用的多了,再做总结。


 

  • 首先指针是用来存放内存地址的。
  • 指针有不同的类型,各种类型的指针指向各自类型的数据地址。
  • int *p 定义一个int类型的指针。
  • int *p[n] 定义n个指向int类型的指针。
  • int (*p)[n] 指向int类型数组的指针,数组大小为n。
  • int *p() 返回值为int类型指针的函数。
  • int (*p)() 指向函数的指针,该数据返回int类型。
  • int **p 指向指针的指针。
  • 指针在2位操作系统中本身会占用4个字节,理论上64位的就是8字节。

 

meiking   2011-11-01 15:34:06 阅读:83  评论:0  引用:0
〖摘要:〗

在网上看到别人用3个小时用SWING写了个俄罗斯方块,以为很简单,昨天就试着用GWT练习一下。结果花了近6个小时,算法参考了别人的,流程自己实现的。编译完是js,目前还存在兼容问题,只支持ie浏览器,不知道是GWT的bug还是程序bug。

成品下载地址:war.war

实现原理就是用用数组记录游戏场景的数据。

核心源代码 java,css文件在成品包里面

package com.noname.games.client;

import java.util.Random;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.*;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;

/**
 *
 * @author meiking
 */
public class Scene extends Composite implements KeyDownHandler {

  interface Binder extends UiBinder<Widget, Scene> {
  };
  private static Binder binder = GWT.create(Binder.class);
  private static final String FRAME_CLASS = "frame";
  private static final String I_CLASS = "grid-i";
  private static final String L_CLASS = "grid-l";
  private static final String J_CLASS = "grid-j";
  private static final String S_CLASS = "grid-s";
  private static final String Z_CLASS = "grid-z";
  private static final String O_CLASS = "grid-o";
  private static final String T_CLASS = "grid-t";
  private static final String NONE_CLASS = "grid-none";
  @UiField
  Grid gameScene, nextGridPanel;
 
  @UiField
  HTML scoresPanel, linesPanel, levelPanel;
 
  @UiField
  Button start;
 
  DialogBox dialog;
 
  Timer timer;
 
  int[][][][] grids = new int[][][][]{
    { //I
      {{0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}},
      {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}},
      {{0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}},
      {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}
    },
    { //L
      {{0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}},
      {{0, 0, 0, 0}, {0, 1, 1, 1}, {0, 1, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}},
      {{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 1, 1, 1}, {0, 0, 0, 0}}
    },
    { //J
      {{0, 0, 1, 0}, {0, 0, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}},
      {{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 1}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}},
      {{0, 0, 0, 0}, {0, 1, 1, 1}, {0, 0, 0, 1}, {0, 0, 0, 0}}
    },
    { //S
      {{0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}},
      {{0, 0, 1, 1}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}},
      {{0, 0, 1, 1}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
    },
    { //Z
      {{0, 0, 1, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}},
      {{0, 0, 1, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}
    },
    { //O
      {{0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},
      {{0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
    },
    { //T
      {{0, 1, 1, 1}, {0, 0, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},
&n
继续阅读其余的  25196 字
meiking   2011-10-16 15:32:58 阅读:174  评论:1  引用:0

公司要山寨亚马逊的EC2,今天简单调研了一下亚马逊的EC2收费内容,发现个不错的东西。英文不好,可能有些理解的东西不对,给出网址: http://aws.amazon.com/free/

免费试用的东西一般会给一些限制,不过亚马逊还是很大方的,下面的内容都是每个月的免费额度,如果使用内容超过了额度则需要支付费用,个人觉得费用相对自己租虚机的性价比来算不贵。

免费内容如下:

  • 提供每个月750小时的Linux小型虚机实例(613MB内存,32位和64位都支持),750÷24=31.25
  • 750小时的负载均衡,15G+的负载数据。
  • 10G的EBS(虚机的挂载存储,可以简单理解成U盘这样的东西),10万+次的EBS I/O,1GB的快照存储空间,1万次的快照创建请求和1万次的恢复请求。
  • 5G的S3存储容量(应该是对象存储,当然也包括文件),2万次的读取请求和2万次的存储请求。
  • 30G的互联网传输数据,分别时15GB in,15GB out。
  • 25小时的SimpleDB(关系型数据库)服务,以及1G的数据库空间。
  • 100,000 Requests of Amazon Simple Queue Service(不了解,似乎和分布式计算有关系的服务)
  • 100,000 Requests, 100,000 HTTP notifications and 1,000 email notifications for Amazon Simple Notification Service(不了解,感觉是通知相关的东西,10万次的HTTP监控和1000次的邮件通知?)
  • 10 Amazon Cloudwatch metrics, 10 alarms, and 1,000,000 API requests(不了解)
刚刚看了以下青草地的awstats统计,免费的似乎还不够用。放个人博客或者作为VPN ssh等服务还是不错的选择。如果想把网站架设上去并且使用他们的存储的话,需要根据S3和SimpleDB的接口进行开发,但是应该没有难度。
meiking   2011-09-08 16:06:09 阅读:765  评论:3  引用:0

Linux命令行模式下rm是将文件彻底删除,操作起来比较危险。

开发机使用的是Ubuntu比较好解决这个问题:

1. 安装trash-cli工具,其实就是回收站的命令行模式:

sudo apt-get install trash-cli

2.给trash命令添加别名"rm",覆盖系统rm命令。

vi ~/.profile

加入:alias rm="trash"

执行:source ~/.profile

3.上回收站找回删除的文件。

删除成功的文件会放入系统回收站中,位置:~/.local/share/Trash/files。

 

常见rm的参数trash都支持,所以不用担心习惯问题。

meiking   2011-07-27 14:48:04 阅读:718  评论:3  引用:0

公司面试题里有一道是计算一个字符串里面字母出现频率最高的一个字母,想起余老师和haohao之前也做过一道这题,所以就动手做了一下。来公司面试的人大多使用的是Map<String, Integer> 方法,然后再解析字符串的方法中用的方法有substring、charAt,还有用toCharArray,一般用toCharArray并且程序正确的都会优先考虑一下的,用其它方法一般比较危险。

hofman: http://www.zhuoda.org/hofman/96281.html
haohao: http://www.zhuoda.org/haohao/96277.html

测试用例是读本地一个319M的文本文件,用余老师程序跑了一下,平均用时在9秒左右。

花掉的时间大致如下:
读文件:  600ms
System.arraycopy: 5600-600 = 5000ms
计算字频: 9000-5600 = 3400ms
细算的话,计算过程中做判断也会占用一部份时间,具体多少时间一会儿会计算。

首先看读文件上是否可以优化?
上次做测试发现buffer的大小会影响读取的速度,但具体规律没搞明白,公司有几个高手,特地去请教了一下为什么buffer的大小会影响文件读取文件?得知操作文件系统中最小的文件块数为4096,也就是说不管多大的文件都是由N个4096byte大小的块组成的。将buffer大小改成4096的倍数试验了一下,结果很明显,大概用时为200ms左右,倍数大小没有关系。

再看计算过程
System.arraycopy方法是为了得到一个总的byte array,然后再做计算,就这个面试题而言,其实可以省去,我是直接使用buffer来做的计算,结果很明显,省掉了5000ms。

计算词频
那份319M的文件大概含有字符数量为: 334245930,haohao程序中大概做了下面这些次数的运算:(c >= 'a' && c <= 'z')、(c >= 'A' && c <= 'Z')、(25 - ('z' - c)) 2*334245930 + 2*334245930 * 1*334245930。感觉这些运算可必没必要在大循环里运算,因为大部份运算都是重复的。我的程序中大循环里只做了一次运算(if (b > -1))1*334245930,把重复的运算放到了外面一次完成,大概减少了 4*334245930次运算,结果耗时:800ms。

总用时一般在1100ms左右,下面是代码,回头有时间再想想是否还有改进空间

package chars;

import java.io.*;
import java.util.*;

public class ComputingChartsNum
{

  public static void main(String[] args)
  {
    String path = "/home/yoyo/Documents/china.txt";
    long started = System.currentTimeMillis();
    run(path);

    long ended = System.currentTimeMillis();

    System.out.println("Used : " + (ended - started));

    for (int i = 65; i < 91; i++) {
      out[i] += out[i + 32];
      System.out.println((char) i + ":" + out[i]);
    }
  }

  static int[] out = new int[123];

  private static void run(String path)
  {
    InputStream is = null;

    try {
      is = new FileInputStream(new File(path));
      byte[] charts = new byte[4096];
      int index = 0;
      while ((index = is.read(charts)) != -1) {
        int i = 0;
        for (byte b : charts) {
          if (i > index) { //FIXED A BUG
            break;
          }
          if (b > -1) {
            out[b]++;
          }
          i++;
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (is != null) {
        try {
          is.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

Edit on 2011-08-03 19:40
更新4096Byte的理解

系统空间(包括内存)由一个链表来存储N个4096个空间的地址,决定读取速度确实和次数有关系,硬盘的数据当然还和连续性有关。比如读取一个4096000大小的硬盘文件,无论buffer大小是4096000或者是4096都是一定会做1000读取至内存操作,而不是InputStream.read()次数。

meiking   2011-07-21 22:40:57 阅读:452  评论:8  引用:0

基本上感觉自己学习的东西都是学会了立马就用,很少有机会能专门花时间去学习一些东西,近些时候不忙,准备把公司的面试题全做一遍,难的倒是不多,但是很多人都不会做,问题就是出在实践上。

言归正传。多线程就目前而言,纯是兴趣上的学习,并没有真实的应用场景。以前觉java多线程很乱,很多概念没似懂非懂,但是实战中写几个实例就一目了然了。

昨天练习线程安全时提到了synchronized关键字,其作用原理其实就是把一个或者一部份资源锁住,只允许当前这个进程使用。我理解线程同步就让各个线程之间能够控制资源的分配,比方说锁定资源,释放资源以及等待资源的释放。

下面这个例子之前在网上看到的,自己动手实现了一遍。主要思路就是有一个盘子,有两个人去对盘子操作,其中一个负责放鸡蛋,另一个只负责取走鸡蛋。当盘子里有鸡时,不能再放,当盘子是空的时候无法再取走产鸡蛋。

package threads;

public class TestSynchronous
{
  public static int size = 50;

  public static void main(String[] args)
  {
    Plate plate = new Plate();
    new Thread1(plate).start();
    new Thread2(plate).start();
  }

  public static class Thread1 extends Thread //负责放鸡蛋的人
  {
    Plate plate;

    public Thread1(Plate plate)
    {
      this.plate = plate;
    }

    public void run()
    {
      for (int i = 0; i < size; i++) {
        synchronized (plate) {
          if (plate.hasEgg()) {
            try {
              plate.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
          plate.putEgg("egg");
          System.out.println("put egg.");
          plate.notify();
        }
      }
    }
  }

  public static class Thread2 extends Thread //负责取走产鸡蛋的进度
  {
    Plate plate;

    public Thread2(Plate plate)
    {
      this.plate = plate;
    }

    public void run()
    {
      for (int i = 0; i < size; i++) {
        synchronized (plate) {
          if (!plate.hasEgg()) {
            try {
              plate.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
          plate.eggAway();
          System.out.println("take away egg.");
          plate.notify();
        }
      }
    }
  }

  public static class Plate //盘子
  {
    Object egg;

    public Plate()
    {
    }

    public void putEgg(Object egg)
    {
      this.egg = egg;
    }

    public void eggAway()
    {
      this.egg = null;
    }

    public boolean hasEgg()
    {
      return egg != null;
    }
  }
}
meiking   2011-07-13 16:45:46 阅读:390  评论:0  引用:0

Telnet

它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。传统telnet连线会话所传输的资料并未加密。

Traceroute

Windows系统称为tracert,是一种电脑网络工具。它可显示分组在IP网络经过的路由器的IP地址。

原理
程序利用增加存活时间(TTL)值来实现其功能的。每当分组经过一个路由器,其存活时间就会减一。当其存活时间是1时,主机便取消分组,并传送一个ICMP TTL分组给原分组的发出者。
程序发出的首3个分组TTL值是1,之后3个是2,如此类推,它便得到一连串分组路径。注意IP不保证每个分组走的路径都一样。

以后接触到继续补充。

meiking   2011-07-13 10:44:46 阅读:70  评论:1  引用:0

java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉。但是无法避免的是unchecked exception,也就是RuntimeException,当抛出异常时子线程会结束,但不会影响主线程。

通过try catch是无法捕获子线程异常的,Thread对象提供了setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法用来获取线程中产生的异常。

实战:

package threads;

import java.lang.Thread.UncaughtExceptionHandler;

public class TextException
{
  public static void main(String[] args)
  {
    Test test = new Test();
    test.setUncaughtExceptionHandler(new UncaughtExceptionHandler()
    {
      public void uncaughtException(Thread t, Throwable e)
      {
        System.out.println(t.getName() + " : " + e.getMessage());
        // TODO
      }
    });
  }

  public static class Test extends Thread
  {
    public Test()
    {
    }

    public void run()
    {
      throw new RuntimeException("just a test");
    }
  }
}
meiking   2011-07-12 16:40:40 阅读:439  评论:0  引用:0
Copyright@2004-2010 powered by YuLog