月度归档:2011 年四月

Servlet 输出中文乱码的新收获(1) [转]

又碰到servlet 输出中文乱码的问题,恼火。研究了一下,有了新的发现和认识。
原始代码:
java 代码
  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. PrintWriter pw = response.getWriter();
  3. response.setCharacterEncoding(“utf-8″);
  4. response.setContentType(“text/html; charset=utf-8″);
  5. pw.print(“中文”);
  6. }
无论把3、4两句改成gbk还是utf-8,页面访问到的一律是??
一怒之下用wpe抓包,发现无论设为utf-8还是gbk抓到的均为
HTTP 代码
  1. HTTP/1.1 200 OK
  2. Server: Apache-Coyote/1.1
  3. Content-Type: text/html;charset=ISO-8859-1
  4. Content-Length: 2
  5. Date: Thu, 08 Mar 2007 06:04:55 GMT
  6. ??
说明3、4两句没起作用,检查代码,尝试把2和三四顺序调整,乱码问题解决。
检查api文档,发现说明如下
PrintWriter getWriter() throws IOException
Returns a PrintWriter object that can send character text to the client. The PrintWriter uses the character encoding returned by getCharacterEncoding(). If the response’s character encoding has not been specified as described in getCharacterEncoding (i.e., the method just returns the default value ISO-8859-1), getWriter updates it to ISO-8859-1.
推断getWriter()返回的PrintWriter使用的charactor encoding是在这个函数返回时即已确定的,但到底是返回的PrintWriter内部属性还是运行时的控制,未找到依据。
查看 tomcat中setCharacterEncoding方法的实现时发现如下代码:
java 代码
  1. public void setCharacterEncoding(String charset) {
  2. if (isCommitted())
  3. return;
  4. // Ignore any call from an included servlet
  5. if (included)
  6. return;
  7. // Ignore any call made after the getWriter has been invoked
  8. // The default should be used
  9. if (usingWriter)
  10. return;
  11. coyoteResponse.setCharacterEncoding(charset);
  12. isCharacterEncodingSet = true;
  13. }
其中usingWriter 标志为getPrinteWriter方法中设定,可见其控制逻辑为一旦返回了PrintWriter,本函数即不再生效。但是上述的推断没有进一步的证据。
同时我们发现只有usingWriter标志,却没有usingOutputStream标记。猜测使用ServletOutputStream 输出不受此限制,经测试写出如下代码。
java 代码
  1. ServletOutputStream out = response.getOutputStream();
  2. out.print(“中文”);
  3. //情况1:正常,浏览器按utf-8方式查看
  4. //response.setContentType(“text/html; charset=utf-8″);
  5. //情况2:浏览器缺省按简体中文查看,手动设为utf-8方式查看正常
  6. //response.setCharacterEncoding(“utf-8″);
说明:这种方式不仅不需要在调用getOutputStream()之前设定字符集,甚至在print输出后设定都有效。
(居然有字数限制,并且提示都没有,内容就丢了,郁闷。只好分两篇了,待续)

搭建基于Eclipse的Hadoop测试环境[转]

本机的环境如下:

Eclipse 3.6

Hadoop-0.20.2

Hive-0.5.0-dev

1. 安装hadoop-0.20.2-eclipse-plugin的插件。注意:Hadoop目录中的\hadoop-0.20.2\contrib \eclipse-plugin\hadoop-0.20.2-eclipse-plugin.jar在Eclipse3.6下有问题,无法在 Hadoop Server上运行,可以从http://code.google.com/p/hadoop-eclipse-plugin/下载

2. 选择Map/Reduce视图:window ->  open pers.. ->  other.. ->  map/reduce

3. 增加DFS Locations:点击Map/Reduce Locations—> New Hadoop Loaction,填写对应的host和port

1
2
3
4
5
6
7
8
9
10
Map/Reduce Master:
Host: 10.10.xx.xx
Port: 9001
DFS Master:
Host: 10.10.xx.xx(选中 User M/R Master host即可)
Port: 9000
User name: root

更改Advance parameters 中的 hadoop.job.ugi, 默认是 DrWho,Tardis, 改成:root,Tardis。如果看不到选项,则使用Eclipse -clean重启Eclipse
否则,可能会报错org.apache.hadoop.security.AccessControlException

4. 设置本机的Host:

1
2
3
4
5
10.10.xx.xx zw-hadoop-master. zw-hadoop-master

#注意后面需要还有一个zw-hadoop-master.,否则运行Map/Reduce时会报错:
java.lang.IllegalArgumentException: Wrong FS: hdfs://zw-hadoop-master:9000/user/root/oplog/out/_temporary/_attempt_201008051742_0135_m_000007_0, expected: hdfs://zw-hadoop-master.:9000
    at org.apache.hadoop.fs.FileSystem.checkPath(FileSystem.java:352)

5. 新建一个Map/Reduce Project,新建Mapper,Reducer,Driver类,注意,自动生成的代码是基于老版本的Hadoop,自己修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.sohu.hadoop.test;

import java.util.StringTokenizer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

public class MapperTest extends Mapper<Object, Text, Text, IntWritable> {
    private final static IntWritable one = new IntWritable(1);

    public void map(Object key, Text value, Context context)
            throws IOException, InterruptedException {
        String userid = value.toString().split("[|]")[2];
        context.write(new Text(userid), new IntWritable(1));
    }
}

package com.sohu.hadoop.test;

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class ReducerTest extends Reducer<Text, IntWritable, Text, IntWritable> {

    private IntWritable result = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values, Context context)
            throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable val : values) {
            sum += val.get();
        }
        result.set(sum);
        context.write(key, result);
    }
}

package com.sohu.hadoop.test;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.GzipCodec;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class DriverTest {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        String[] otherArgs = new GenericOptionsParser(conf, args)
                .getRemainingArgs();
        if (otherArgs.length != 2)
        {
            System.err.println("Usage: DriverTest <in> <out>");
            System.exit(2);
        }
        Job job = new Job(conf, "Driver Test");
        job.setJarByClass(DriverTest.class);
        job.setMapperClass(MapperTest.class);
        job.setCombinerClass(ReducerTest.class);
        job.setReducerClass(ReducerTest.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        conf.setBoolean("mapred.output.compress", true);
        conf.setClass("mapred.output.compression.codec", GzipCodec.class,CompressionCodec.class);

        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

6. 在DriverTest上,点击Run As —> Run on Hadoop,选择对应的Hadoop Locaion即可

mysql-bin.000001文件的来源及处理方法[转]

用ports安装了mysql以后,过一段时间发现/var空间不足了,查一下,会发现是mysql-bin.000001、mysql-bin.000002等文件占用了空间,那么这些文件是干吗的?这是数据库的操作日志,例如UPDATE一个表,或者DELETE一些数据,即使该语句没有匹配的数据,这个命令也会存储到日志文件中,还包括每个语句执行的时间,也会记录进去的。

这样做主要有以下两个目的:
1:数据恢复
如果你的数据库出问题了,而你之前有过备份,那么可以看日志文件,找出是哪个命令导致你的数据库出问题了,想办法挽回损失。
2:主从服务器之间同步数据
主服务器上所有的操作都在记录日志中,从服务器可以根据该日志来进行,以确保两个同步。

处理方法分两种情况:
1:只有一个mysql服务器,那么可以简单的注释掉这个选项就行了。
vi /etc/my.cnf把里面的log-bin这一行注释掉,重启mysql服务即可。
2:如果你的环境是主从服务器,那么就需要做以下操作了。
A:在每个从属服务器上,使用SHOW SLAVE STATUS来检查它正在读取哪个日志。
B:使用SHOW MASTER LOGS获得主服务器上的一系列日志。
C:在所有的从属服务器中判定最早的日志,这个是目标日志,如果所有的从属服务器是更新的,就是清单上的最后一个日志。
D:清理所有的日志,但是不包括目标日志,因为从服务器还要跟它同步。
清理日志方法为:
PURGE MASTER LOGS TO ‘mysql-bin.010′;
PURGE MASTER LOGS BEFORE ’2008-12-19 21:00:00′;

如果你确定从服务器已经同步过了,跟主服务器一样了,那么可以直接RESET MASTER将这些文件删除。

======================================

之前发现自己10G的服务器空间大小,用了几天就剩下5G了,自己上传的文件才仅仅几百M而已,到底是什么东西占用了这么大空间呢?今天有时间彻底来查了一下:

mysql-log

看下上面的目录web根目录是放在/home 里面的,所有文件加起来才不到300M,而服务器上已经占用了近5G空间,恐怖吧,最后经我一步一步查询得知,原来是这个文件夹占了非常多的空间资源:

mysql-log1

原来如此,是mysql文件夹下的var目录占用空间最大,那里面是啥 内容呢?我们来看下:

mysql-log2

发现了如此多的 mysql-bin.0000X文件,这是什么东西呢?原来这是mysql的操作日志文件.我才几十M的数据库,操作日志居然快3G大小了.

如何删除mysql-bin.0000X 日志文件呢?

红色表示输入的命令.

[root@jiucool var]# /usr/local/mysql/bin/mysql -u root -p
Enter password:  (输入密码)
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 264001
Server version: 5.1.35-log Source distribution

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> reset master; (清除日志文件)
Query OK, 0 rows affected (8.51 sec)

mysql>

好了,我们再来查看下mysql文件夹占用多少空间?

[root@jiucool var]# du -h –max-depth=1 /usr/local/mysql/
37M     /usr/local/mysql/var
70M     /usr/local/mysql/mysql-test
15M     /usr/local/mysql/lib
448K    /usr/local/mysql/include
2.9M    /usr/local/mysql/share
7.6M    /usr/local/mysql/libexec
17M     /usr/local/mysql/bin
11M     /usr/local/mysql/docs
2.9M    /usr/local/mysql/sql-bench
163M    /usr/local/mysql/

好了,看一下,整个mysql 目录才占用163M大小!OK,没问题,既然mysql-bin.0000X日志文件占用这么大空间,存在的意义又不是特别大,那么我们就不让它生成吧.

[root@jiucool var]# find / -name my.cnf

找到了my.cnf 即mysql配置文件,我们将log-bin=mysql-bin 这条注释掉即可.

# Replication Master Server (default)
# binary logging is required for replication
#log-bin=mysql-bin

重启下mysql吧.

OK,至此,操作完成. 以后再不会因为就几十M的数据库大小生成N个G的日志文件啦.

这些个日志文件太恐怖了,我搬到这新VPS来才二十天左右,还不到一个月日志文件居然就近3个G大小,如果一两个月我不清除日志文件这还得了!

用 PHP 构建自定义搜索引擎[转]

在 Internet 时代,人们希望信息能够像快餐一样被打包起来:能够快速无障碍使用,并且分为很小的单位(或者是以字节 大小为单位?)。实际上,为了满足急躁而又渴求信息的用户的需求,甚至最普通的 Web 站点现在都要求具有快速浏览样式的各种菜单:

  • RSS 是比萨快递员,会把新鲜出炉的比萨送上门。
  • 网络日志是当地的中餐馆,为您献上喜爱的风味菜肴。
  • 论坛是家常便饭(或者可能更恰当地说,“动物屋” 中抢夺食物的场景)。
  • 而搜索就像在当地的餐厅吃自助晚餐一样:不断将想吃的食物填满盘子就行,只要您的食道 —— 还有您的椅子 —— 撑得住。

幸运的是,PHP 开发人员可以找到各种 RSS、blog 和论坛软件来创建或者改进站点。而且,虽然 Google 和其他搜索站点几乎无所不能并且执行过滤通信,但是搜索引擎并不一定会良好地适应各个站点。

例如,如果 Web 站点提供成百上千的全新和翻新的保时捷汽车零件,Google 可能通过诸如 “Carrera parts” 之类的广义搜索找到您的站点,但是对于更具体的 “used 1991 Porsche 911 Targa headlight bezel” 查询,它可能不会得到精确结果。

如果站点内容高度专业化,或者访问者期望搜索功能与现实工作流类似,那么最好在 Web 的全局搜索引擎基础上增加一个为您的站点量身定做的本地搜索系统(有关专业化搜索的更多实例,请参阅 “A needle in a billion haystacks”)。

通过本文了解如何向 PHP 站点中添加一个快速、高效、开源和免费的搜索引擎。本文没有开发可见的 Web 站点。相反,重点讨论交付有效搜索结果所需的组件:数据库、索引、搜索引擎和 PHP 应用程序编程接口 (API)。

访问优秀的 sphinx

要为站点提供自定义搜索功能,您必须有数据源和搜索该数据源的功能。对于 Web 应用程序,数据源通常是一个关系数据库,其中内置了一些搜索功能(Equality 是一个简单的搜索运算符,与 SQL 运算符 LIKE 一样)。但是,一些搜索可能比数据库可以执行的搜索更加具体,或者搜索可能过于复杂,而导致固有的 SQL JOIN 反应迟钝。

海底捞针

许多站点提供特定于某一个行业、职业或者娱乐的内容,例如医药、法律、音乐和汽车维修。深入研究这些内容可能要求使用特殊工具或者培训,或者仅需要使用一个索引来生成相关的实用结果。

下面是一些需要定制搜索系统的常见搜索场景:

  • 查找 Joe Hockey 所撰写的关于斯坦利杯 (Stanley Cup) 的所有文章。
  • 查找 HP LaserJet 3015 All-in-One 打印机的最新驱动程序。
  • 查找 Dinosaur Jr. 参与大卫深夜脱口秀节目的电视片段。

要加速搜索,您可以重新安排表,并由此简化底层查询(表和 SQL 查询优化高度依赖于模式和引擎。可通过在线搜索查找有关数据库性能的各种文章和书籍)。此外,您可以添加一个专门化的搜索引擎。应用哪种形式的搜索引擎还依赖于数据的形式(和数量)和预算。有许多选择可用:您可以将一个 Google 工具连接到您的网络中,购买 Endeca 或其他大型商业搜索产品,或者尝试 Lucene。但是在很多情况下,使用商业产品都有点小题大做,或者浪费运营预算,并且 Lucene 在 2007 年 7 月编写时并未提供 PHP API。

作为一个备选方案,考虑一下 Sphinx,它是一种开源和免费的搜索引擎,可以非常快速地搜索文本。例如,在一个几乎有 300,000 行及五个索引列(每列包含大约 15 个单词)的活动数据库中,Sphinx 可以在 1/100 秒内得到 “这些单词中任何一个单词” 的搜索结果(在运行 Debian Linux® Sarge 的 2-GHz AMD Opteron 处理器、1 GB RAM 的计算机上)。

Sphinx 提供了大量功能,包括:

  • 它可以为能够表示为字符串的所有数据建立索引。
  • 它可以以各种方式为相同数据建立索引。对于多个索引,每个索引都针对特定目的而定制,您可以选择最适当的索引来优化搜索结果。
  • 它可以把属性与每条索引数据关联起来。然后您可以使用一个或多个属性来进一步过滤搜索结果。
  • 它支持词法,因此搜索单词 “cats” 还会找到词根 “cat”。
  • 您可以在许多计算机中分发 Sphinx 索引,从而提供故障恢复功能。
  • 它可以创建任意长度的单词前缀索引和可变长度的中缀子字符串的索引。例如,一个零件号可以是 10 个字符宽。前缀索引将匹配位于字符串开头处的所有可能的子字符串。中缀索引将匹配在字符串内任意位置的子字符串。
  • 您可以在 MySQL V5 内将其作为存储引擎运行,降低使用其他守护程序的需求(通常被视为另一个故障点)。

您可以在 Sphinx 源代码附带的 README 文件中或通过在线资料找到完整的功能列表。Sphinx Web 站点还列出了已经部署了 Sphinx 的若干个项目。

Sphinx 是用 C++ 编写、用 GNU 编译器构建、支持 64 位支持平台,并在 Linux、UNIX®、Microsoft® Windows® 和 Mac OS X 上运行。构建 Sphinx 十分简单:下载并解压缩代码,然后运行 ./configure && make && make install 命令。

默认情况下,Sphinx 实用程序将被安装到 /usr/local/bin/ 中,并且所有 Sphinx 组件的配置文件都位于 /usr/local/etc/sphinx.conf 中。

Sphinx 有三个组件:索引生成器、搜索引擎和命令行 search 实用程序:

  • 索引生成器被称为索引器。它将查询数据库,为结果的每行中的每列建立索引,并且将每个索引条目绑定到行的主键上。
  • 搜索引擎是名为 searchd 的守护程序。该守护程序将接收搜索词和其他参数,快速遍历一个或多个索引,并返回结果。如果找到匹配,searchd 将返回一个主键数组。对于这些键,应用程序可以针对相关数据库运行查询来查找包含匹配的完整记录。Searchd 将在端口 3312 上通过套接字连接与应用程序进行通信。
  • 便捷的 search 实用程序使您可以从命令行构造搜索而无需编写代码。如果 searchd 返回匹配,则 search 将查询数据库并显示匹配集中的行。search 实用程序对于调试 Sphinx 配置和执行临时搜索十分有用。

此外,Sphinx 的作者 Andrew Aksyonoff 和其他贡献者为 PHP、Perl、C/C++ 和其他编程语言提供了 API。

搜索车身零件

假定 Body-Parts.com 出售车身零件 —— 挡泥板、铬、缓冲器等 —— 用于珍贵且值得收藏的汽车。正如在现实世界中,Body Parts 站点的访问者很可能按制造商(比如保时捷或制造同类零件的第三方制造商)、零件号、产地、车型、年份、条件(二手、全新、翻新)以及描述或者这些属性的某种组合来搜索零件。

要构建 Body Parts 搜索功能,让我们使用 MySQL V5.0 作为数据存储并使用 Sphinx search 守护程序来提供快速而精确的文本搜索。MySQL V5.0 是一个功能强大的数据库,但是它的增强型全文本搜索功能并不特别丰富。实际上,它仅限于 MyISAM 表 —— 不支持外键的一种表格式,因此使用有限。

清单 1 至清单 4 显示了与此示例相关的 Body Parts 模式的部分代码。您将分别看到 Model(清单 1)、Assembly(清单 2)、Inventory(清单 3)和 Schematic(清单 4)表。

Model 表

清单 1 中所示的 Model 表十分简单:label 列将列举车型的名称 (“Corvette”);description 使用客户友好方式进行描述(“两门跑车;第一年引入”);而 begin_production 和 end_production 分别表示开始生产和结束生产该车型的年份。由于前述列中的值并不惟一,因此使用一个独立 ID 表示每四个这样的元素(label、description、begin_production、end_production),并且是其他表中的外键。
清单 1. 车身零件 Model 表

CREATE TABLE Model (
  id int(10) unsigned NOT NULL auto_increment,
  label varchar(7) NOT NULL,
  description varchar(256) NOT NULL,
  begin_production int(4) NOT NULL,
  end_production int(4) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

下面是 Model 表的一些样例数据:

INSERT INTO Model
  (`id`, `label`, `description`, `begin_production`, `end_production`)
VALUES
  (1,'X Sedan','Four-door performance sedan',1998,1999),
  (3,'X Sedan','Four door performance sedan, 1st model year',1995,1997),
  (4,'J Convertible','Two-door roadster, metal retracting roof',2002,2005),
  (5,'J Convertible','Two-door roadster',2000,2001),
  (7,'W Wagon','Four-door, all-wheel drive sport station wagon',2007,0);

Assembly 表

assembly 是一个子系统,例如汽车上安装的传动装置或所有玻璃。车主使用部件图及相关零件列表来查找备件。清单 2 中所示的 Assembly 表也十分简单:它将把一个惟一 ID 与部件标签和描述关联起来。
清单 2. Assembly 表

CREATE TABLE Assembly (
  id int(10) unsigned NOT NULL auto_increment,
  label varchar(7) NOT NULL,
  description varchar(128) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

继续示例,下面是 Assembly 表的一些样例数据:

INSERT INTO Assembly
  (`id`, `label`, `description`)
VALUES
  (1,'5-00','Seats'),
  (2,'4-00','Electrical'),
  (3,'3-00','Glasses'),
  (4,'2-00','Frame'),
  (5,'1-00','Engine'),
  (7,'101-00','Accessories');

Inventory 表

Inventory 表是汽车零件的典范列表。零件 —— 例如螺钉或灯泡 —— 可能用于每辆汽车和多个部件中,但是零件只在 Inventory 表中显示一次。Inventory 表中的每行包含:

  • 使用了惟一的 32 位整数 serialno 标识行。
  • 字母数字零件号(此零件号惟一并且可以用作主键。但是,由于它可以包含字母数字字符,因此它不适于与 Sphinx 结合使用,Sphinx 要求索引的每条记录都有一个惟一的 32 位整型键)。
  • 文本描述。
  • 价格。

Inventory 表的规范如清单 3 中所示:
清单 3. Inventory 表

CREATE TABLE Inventory (
  id int(10) unsigned NOT NULL auto_increment,
  partno varchar(32) NOT NULL,
  description varchar(256) NOT NULL,
  price float unsigned NOT NULL default '0',
  PRIMARY KEY (id),
  UNIQUE KEY partno USING BTREE (partno)
) ENGINE=InnoDB;

零件的(部分)列表可能如下面所示:

INSERT INTO `Inventory`
  (`id`, `partno`, `description`, `price`)
VALUES
  (1,'WIN408','Portal window',423),
  (2,'ACC711','Jack kit',110),
  (3,'ACC43','Rear-view mirror',55),
  (4,'ACC5409','Cigarette lighter',20),
  (5,'WIN958','Windshield, front',500),
  (6,'765432','Bolt',0.1),
  (7,'ENG001','Entire engine',10000),
  (8,'ENG088','Cylinder head',55),
  (9,'ENG976','Large cylinder head',65);

Schematic 表

Schematic 表将把零件与部件和车型版本绑定在一起。因此,将使用 Schematic 表来查找组装 1979 J Class 敞篷车引擎的所有零件。Schematic 表中的每行都有一个惟一 ID,一个引用 Inventory 表行的外键,一个标识部件的外键,以及用于引用 Model 表中特定型号和版本的另一个键。各行如清单 4 所示:
清单 4. Schematic 表

CREATE TABLE Schematic (
  id int(10) unsigned NOT NULL auto_increment,
  partno_id int(10) unsigned NOT NULL,
  assembly_id int(10) unsigned NOT NULL,
  model_id int(10) unsigned NOT NULL,
  PRIMARY KEY (id),
  KEY partno_index USING BTREE (partno_id),
  KEY assembly_index USING BTREE (assembly_id),
  KEY model_index USING BTREE (model_id),
  FOREIGN KEY (partno_id) REFERENCES Inventory(id),
  FOREIGN KEY (assembly_id) REFERENCES Assembly(id),
  FOREIGN KEY (model_id) REFERENCES Model(id)
) ENGINE=InnoDB;

为了强化表的意图,下面是 Schematic 中的一张小型行列表:

INSERT INTO `Schematic`
  (`id`, `partno_id`, `assembly_id`, `model_id`)
VALUES
  (1,6,5,1),
  (2,8,5,1),
  (3,1,3,1),
  (4,5,3,1),
  (5,8,5,7),
  (6,6,5,7),
  (7,4,7,3),
  (8,9,5,3);

搜索表

定义了这些表后,就可以轻松地响应很多搜索:

  • 显示特定型号的所有版本
  • 列出装配特殊型号和版本所需的所有部件
  • 显示构成特定型号和版本的特殊部件的所有零件

但是很多搜索代价较大:

  • 查找所有模型和版本中出现零件号开头为 “WIN” 的所有零件
  • 查找描述中有 “lacquer” 或 “paint” 的那些零件
  • 查找描述中有 “black leather” 的所有零件
  • 查找描述中有 “paint” 的所有 2002 J 系列零件

这些搜索中的每个搜索都要求使用长篇的 JOIN 子句或代价高昂的 LIKE 子句,尤其是在 Inventory 表和 Schematic 表十分大时更是如此。而且,复杂的文本搜索完全超出了 MySQL 的能力。要搜索大量文本数据,请考虑构建和使用 Sphinx 索引。

集成 Sphinx 软件

要应用 Sphinx 来解决问题,您必须定义一个或多个数据源以及一个或多个索引。

source 将标识数据库来建立索引,提供验证信息,并且定义查询用以构造每行。数据源可以随意地标识一列或多列作为过滤器,Sphinx 将之称为。您将使用组来过滤结果。例如,单词描述可能得到 900 个匹配。如果只对特定型号的汽车匹配感兴趣,则可以进一步使用型号组进行过滤。

index 将要求获得数据源(即一组数据行)并定义应当如何为已从数据源中提取出来的数据编目。

您将在 sphinx.conf 文件中定义数据源和索引。Body Parts 的数据源是 MySQL 数据库。清单 5 显示了名为 catalog 的数据源的部分定义 —— 指定连接的数据库以及如何建立连接(主机、套接字、用户和密码)的代码片段。
清单 5. 用于访问 MySQL 数据库的设置

source catalog
{
    type                            = mysql

    sql_host                        = localhost
    sql_user                        = reaper
    sql_pass                        = s3cr3t
    sql_db                          = body_parts
    sql_sock                        =  /var/run/mysqld/mysqld.sock
    sql_port                        = 3306

接下来,创建一个查询以生成要被索引的行。通常,将创建 SELECT 子句,可能需要把许多表 JOIN 在一起才能得到行。但这里存在一个问题:搜索型号和年份必须使用 Assembly 表,但是零件号和零件描述只能在 Inventory 表中找到。为此,Sphinx 必须能够把搜索结果与 32 位整型主键绑定在一起。

要获得右侧表单中的数据,需要创建一个视图 —— MySQL V5 中的新结构,它将把来自其他表的列整合到单独的合成虚拟表中。使用视图,各类搜索所需的所有数据都在一个位置,但是活动数据实际上存在于其他表中。清单 6 显示了定义 Catalog 视图的 SQL。
清单 6. Catalog 视图将把数据整合到虚拟表中

CREATE OR REPLACE VIEW Catalog AS
SELECT
  Inventory.id,
  Inventory.partno,
  Inventory.description,
  Assembly.id AS assembly,
  Model.id AS model
FROM
  Assembly, Inventory, Model, Schematic
WHERE
  Schematic.partno_id=Inventory.id
  AND Schematic.model_id=Model.id
  AND Schematic.assembly_id=Assembly.id;

如果用前面所示的表和数据创建名为 body_parts 的数据库,则 Catalog 视图应当类似以下内容:

mysql> use body_parts;
Database changed
mysql> select * from Catalog;
+----+---------+---------------------+----------+-------+
| id | partno  | description         | assembly | model |
+----+---------+---------------------+----------+-------+
|  6 | 765432  | Bolt                |        5 |     1 |
|  8 | ENG088  | Cylinder head       |        5 |     1 |
|  1 | WIN408  | Portal window       |        3 |     1 |
|  5 | WIN958  | Windshield, front   |        3 |     1 |
|  4 | ACC5409 | Cigarette lighter   |        7 |     3 |
|  9 | ENG976  | Large cylinder head |        5 |     3 |
|  8 | ENG088  | Cylinder head       |        5 |     7 |
|  6 | 765432  | Bolt                |        5 |     7 |
+----+---------+---------------------+----------+-------+
8 rows in set (0.00 sec)

在视图中,字段 id 将指回 Inventory 表中的零件条目。partno 和 description 列是要搜索的主要文本,而 assembly 和 model 列用作进一步过滤结果的组。视图就绪后,构造数据源查询就是小事一桩。清单 7 显示了 catalog 数据源定义的其余部分。
清单 7. 查询创建待索引的行

    # indexer query
    # document_id MUST be the very first field
    # document_id MUST be positive (non-zero, non-negative)
    # document_id MUST fit into 32 bits
    # document_id MUST be unique
    sql_query                       = \
            SELECT \
                    id, partno, description, \
                    assembly, model \
            FROM \
                    Catalog;

    sql_group_column                = assembly
    sql_group_column                = model

    # document info query
    # ONLY used by search utility to display document information
    # MUST be able to fetch document info by its id, therefore
    # MUST contain '$id' macro
    #
    sql_query_info          = SELECT * FROM Inventory WHERE id=$id
}

sql_query 必须包括后续查找需要使用的主键,并且它必须包括需要索引和用作组的所有字段。两个 sql_group_column 条目将声明 Assembly 和 Model 可用于过滤结果。并且 search 实用程序将使用 sql_query_info 来查找匹配记录。在查询中,$id 被替换为 searchd 返回的每个主键。

最后一个配置步骤是构建索引。清单 8 显示了数据源 catalog 的索引。
清单 8. 描述 catalog 数据源的一个可能的索引

index catalog
{
    source                  = catalog
    path                    = /var/data/sphinx/catalog
    morphology              = stem_en

    min_word_len            = 3
    min_prefix_len          = 0
    min_infix_len           = 3
}

第 1 行将指向 sphinx.conf 文件中的指定数据源。第 2 行将定义存储索引数据的位置;按照约定,Sphinx 索引将被存储到 /var/data/sphinx 中。第 3 行将允许索引使用英文词法。并且第 5 行至第 7 行将告诉索引器只索引含有三个字符或更多字符的那些单词,并且为每个这样的字符的子字符串创建中缀索引(为了便于引用,清单 9 显示了 Body Parts 的完整示例 sphinx.conf 文件)。
清单 9. Body Parts 的示例 sphinx.conf

source catalog
{
    type                            = mysql

    sql_host                        = localhost
    sql_user                        = reaper
    sql_pass                        = s3cr3t
    sql_db                          = body_parts
    sql_sock                        =  /var/run/mysqld/mysqld.sock
    sql_port                        = 3306

    # indexer query
    # document_id MUST be the very first field
    # document_id MUST be positive (non-zero, non-negative)
    # document_id MUST fit into 32 bits
    # document_id MUST be unique

    sql_query                       = \
            SELECT \
                    id, partno, description, \
                    assembly, model \
            FROM \
                    Catalog;

    sql_group_column                = assembly
    sql_group_column                = model

    # document info query
    # ONLY used by search utility to display document information
    # MUST be able to fetch document info by its id, therefore
    # MUST contain '$id' macro
    #

    sql_query_info          = SELECT * FROM Inventory WHERE id=$id
}

index catalog
{
    source                  = catalog
    path                    = /var/data/sphinx/catalog
    morphology              = stem_en

    min_word_len            = 3
    min_prefix_len          = 0
    min_infix_len           = 3
}

searchd
{
	port				= 3312
	log					= /var/log/searchd/searchd.log
	query_log			= /var/log/searchd/query.log
	pid_file			= /var/log/searchd/searchd.pid
}

底部的 searchd 部分将配置 searchd 守护程序本身。该部分中的条目不言自明。query.log 尤为有用:它将在运行时显示每次搜索并显示结果,例如搜索的文档数和匹配总数。

构建和测试索引

您现在已经准备好为 Body Parts 应用程序构建索引。为此,需要执行以下步骤:

  1. 键入 sudo mkdir -p /var/data/sphinx 创建目录结构 /var/data/sphinx
  2. 假定 MySQL 正在运行,使用如下所示的代码运行索引器来创建索引。

    清单 10. 创建索引

    $ sudo /usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    using config file '/usr/local/etc/sphinx.conf'...
    indexing index 'catalog'...
    collected 8 docs, 0.0 MB
    sorted 0.0 Mhits, 82.8% done
    total 8 docs, 149 bytes
    total 0.010 sec, 14900.00 bytes/sec, 800.00 docs/sec

    注: -all 参数将重构 sphinx.conf 中列出的所有索引。如果不需要重构所有索引,您可以使用其他参数只对部分索引进行重构。

  3. 您现在可以使用如下所示的代码用 search 实用程序测试索引(不必运行 searchd 即可使用 search)。

    清单 11. 用 search 测试索引

    $ /usr/local/bin/search --config /usr/local/etc/sphinx.conf ENG
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    index 'catalog': query 'ENG ': returned 2 matches of 2 total in 0.000 sec
    
    displaying matches:
    1. document=8, weight=1, assembly=5, model=7
            id=8
            partno=ENG088
            description=Cylinder head
            price=55
    2. document=9, weight=1, assembly=5, model=3
            id=9
            partno=ENG976
            description=Large cylinder head
            price=65
    
    words:
    1. 'eng': 2 documents, 2 hits
    
    $ /usr/local/bin/search --config /usr/local/etc/sphinx.conf wind
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    index 'catalog': query 'wind ': returned 2 matches of 2 total in 0.000 sec
    
    displaying matches:
    1. document=1, weight=1, assembly=3, model=1
            id=1
            partno=WIN408
            description=Portal window
            price=423
    2. document=5, weight=1, assembly=3, model=1
            id=5
            partno=WIN958
            description=Windshield, front
            price=500
    
    words:
    1. 'wind': 2 documents, 2 hits
    
    $ /usr/local/bin/search \
    --config /usr/local/etc/sphinx.conf --filter  model 3 ENG
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    index 'catalog': query 'ENG ': returned 1 matches of 1 total in 0.000 sec
    
    displaying matches:
    1. document=9, weight=1, assembly=5, model=3
            id=9
            partno=ENG976
            description=Large cylinder head
            price=65
    
    words:
    1. 'eng': 2 documents, 2 hits

第一条命令 /usr/local/bin/search --config /usr/local/etc/sphinx.conf ENG 在零件号中找到了两个含有 ENG 的结果。第二条命令 /usr/local/bin/search --config /usr/local/etc/sphinx.conf wind 在两个零件描述中找到了子字符串 wind。而第三条命令把结果限定为 model 为 3 的条目。

编写代码

最后,您可以编写 PHP 代码来调用 Sphinx 搜索引擎。Sphinx PHP API 非常小并且易于掌握。清单 12 是一个小型 PHP 应用程序,用于调用 searchd 以得到使用上面所示的最后一条命令得到的相同结果(“在属于型号 3 的名称中找到含有 ‘cylinder’ 的所有零件”)。
清单 12. 从 PHP 调用 Sphinx 搜索引擎

<?php
  include('sphinx-0.9.7/api/sphinxapi.php');

  $cl = new SphinxClient();
  $cl->SetServer( "localhost", 3312 );
  $cl->SetMatchMode( SPH_MATCH_ANY  );
  $cl->SetFilter( 'model', array( 3 ) );

  $result = $cl->Query( 'cylinder', 'catalog' );

  if ( $result === false ) {
      echo "Query failed: " . $cl->GetLastError() . ".\n";
  }
  else {
      if ( $cl->GetLastWarning() ) {
          echo "WARNING: " . $cl->GetLastWarning() . "
";
      }

      if ( ! empty($result["matches"]) ) {
          foreach ( $result["matches"] as $doc => $docinfo ) {
                echo "$doc\n";
          }

          print_r( $result );
      }
  }

  exit;
?>

要测试代码,需要为 Sphinx 创建 log 目录,启动 searchd,然后运行 PHP 应用程序,如下所示:
清单 13. PHP 应用程序

$ sudo mkdir -p /var/log/searchd
$ sudo /usr/local/bin/searchd --config /usr/local/etc/sphinx.conf
$ php search.php 
9
Array
(
    [fields] => Array
        (
            [0] => partno
            [1] => description
        )

    [attrs] => Array
        (
            [assembly] => 1
            [model] => 1
        )

    [matches] => Array
        (
            [9] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [assembly] => 5
                            [model] => 3
                        )

                )

        )

    [total] => 1
    [total_found] => 1
    [time] => 0.000
    [words] => Array
        (
            [cylind] => Array
                (
                    [docs] => 2
                    [hits] => 2
                )

        )
)

输出为 9:匹配的单行的正确主键。如果 Sphinx 找到匹配,相关数组 $result 将包含名为 results 的元素。浏览 print_r() 的输出以查看返回的其他内容。

注意事项:total_found 是在索引中找到的匹配总数,而 found 是返回的结果数。这两者可能不同,因为您可以更改每次返回多少个匹配结果以及要返回哪批匹配结果,哪个结果利于对冗长的结果列表分页。请查看 API 调用 SetLimits()。一个分页示例是用 $cl->SetLimits( ( $page - 1 ) * SPAN, SPAN ) 调用搜索引擎返回第一批、第二批、第三批(依此类推)SPAN 匹配结果,这取决于显示哪个页面。

结束语

Sphinx 还有更多的功能可以利用。我在这里仅仅介绍了最浅显的一部分,但是您现在有一个可以工作的现实示例作为基石来扩展您的技能。

仔细研读随发行版附带的样例 Sphinx 配置文件 /usr/local/etc/sphinx.conf.dist。该文件中的注释将说明每个 Sphinx 参数可以实现的功能;展示如何创建分布式冗余配置;并说明如何继承基本设置以避免源代码及索引中的重复。Sphinx README 文件还是十分丰富的信息源,包括如何将 Sphinx 直接嵌入 MySQL V5 —— 不需要使用守护程序。

下一篇文章中,将探寻比 echo() 和 print_r() 更好的解决方案来调试 PHP 代码。

Sphinx 1.10 实时索引实现——sphinx新特性体验(一)[转]

在2010.7.19,sphinx 1.10-beta 正式发布。本人当时做了一些很简单的测试,体验了一下其实时索引及字符串属性,今天因工作需求,再次使用
sphinx,详细的测试了一下这两个功能。并做一些记录,以供日后查询!

warning:这里只是简单的体验记录及发现的一些问题,并非指南。如需操作,请根据自己的环境调试!
1、软件:sphinx-1.10-beta-win32.zip

下载地址:http://www.sphinxsearch.com/downloads/sphinx-1.10-beta-win32.zip
系统:windows xp

2、安装配置

sphinx window下不需要安装,直接配置即可

解压 sphinx-1.10-beta-win32.zip 至 E:\sphinxserver\sphinx-1.10

复制 E:\sphinxserver\sphinx-1.10\sphinx-min.conf.in E:\sphinxserver\sphinx-1.10\sphinx.conf

编辑sphinx.conf 配置参数

#
# Minimal Sphinx configuration sample (clean, simple, functional)
#

index testrt
{
type            = rt
rt_mem_limit        = 128M

path            = E:/sphinxserver/sphinx-1.10/data/testrt

//utf-8 编码设置,此处只采用一元切分
charset_type        = utf-8
charset_table        = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
ngram_chars        = U+3000..U+2FA1F

//实时索引的字段、属性
rt_field        = title
rt_field        = content
rt_attr_uint        = gid

//字符串属性
rt_attr_string        = content
rt_attr_string        = title

}

indexer
{
mem_limit        = 128M
}

searchd
{
listen            = 9312            #searchd 端口

# 实时索引监听端口,这些采用mysql 41协议,从0.9.9-rc2开始,sphinx searchd守护进程支持mysql二进制网络协议
# 并可通过标准的mysql api存取数据

listen            = 9306:mysql41

log            = E:/sphinxserver/sphinx-1.10/data/log/searchd.log   #自己在对应目录下建立 data和log目录
query_log        = E:/sphinxserver/sphinx-1.10/data/log/query.log
read_timeout        = 5
max_children        = 30
pid_file        = E:/sphinxserver/sphinx-1.10/data/log/searchd.pid
max_matches        = 1000
seamless_rotate        = 1
preopen_indexes        = 0
unlink_old        = 1
workers            = threads # for RT to work
}

3、测试

开启服务端:sphinx 守护进程 searchd

E:\sphinxserver\sphinx-1.10\bin>searchd -c ../sphinx.conf

若无错误,运行并等待接收查询

客户端 :

a、在cli上测试:

C:\>mysql -P9306 -hlocalhost    ##注意,我的机器直接把mysql的路径注册在系统路径,所以直接使用mysql客户端,和以往的索引进程一样,这里不设置权限,若在生产中,请注意使用防火墙进行权限过滤

C:\>mysql -P9306 -hlocalhost
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 1.10-beta (r2420)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>

#插入一条数据

mysql> insert into testrt(id,gid,title,content) values(1,1,'hello sphinx','this
is sphinx test record');

#查询刚才的结果

mysql> select * from testrt where match('sphinx');
+------+--------+------+----------------------------+--------------+
| id   | weight | gid  | content                    | title        |
+------+--------+------+----------------------------+--------------+
|    1 |   2812 |    1 | this is sphinx test record | hello sphinx |
+------+--------+------+----------------------------+--------------+
1 row in set (0.00 sec) #正确命中

mysql> select * from testrt where match('mysql');
Empty set (0.00 sec)    #没有查询到
Query OK, 1 row affected (0.00 sec)

###测试证明刚才的实时索引设置正确

b、在程序端(php)上测试:

<?php

header('Content-type:text/html;charset=utf-8');

//这里我使用专门用来测试sphinx的中文数据

$link = mysql_connect('localhost','root','password');
mysql_query('set names utf8');
mysql_select_db('sphinx',$link);

$sphinxLink = mysql_connect('localhost:9306');

//测试数据

//获取real-time当前最大id

$maxRs = mysql_query('select * from testrt order by id desc limit 1 ');
$maxVal = mysql_result($maxRs,0,'id');

$sets = mysql_query('select co_id,co_name,co_do from sph_comp limit 1,10000',$link);
$i = $maxVal; ##此处必须使用最大值,否则会出现数据插入失败

##注意原先可以使用 insert into values (value),(value)的逗号分隔的值方式,但这里防止内存不足,每次都直接插入索引

while ($row=mysql_fetch_assoc($sets)) {
$sphinxSql = "insert into testrt(id,gid,title,content) values ($i,{$row['co_id']},'{$row['co_name']}','{$row['co_do']}')";
$res = mysql_query($sphinxSql,$sphinxLink);
$i++;
}

//搜索测试,针对中文

$key = '商品信息';

$sql = "select * from testrt where match('{$key}')";
$rs = mysql_query($sql,$sphinx);

while ($row = mysql_fetch_assoc($rs)) {
print_r($row);
}

die;

?>

运行后显示结果:

Array
(
[id] => 347
[weight] => 8588
[gid] => 208
[content] => 商品信息咨询服务。
[title] => 广州市越秀区姿营商品信息咨询服务部
)

至此整个操作完成

centos5.4安装配置mysql5.5.8+sphinx0.9.9

#ready:
#download mysql from : http://www.mysql.com/downloads/mirror.php?id=401062#mirrors
$ wget http://downloads.mysql.com/archives/mysql-5.5/mysql-5.5.8.tar.gz
$ svn co http://sphinxsearch.googlecode.com/svn/trunk sphinx-trunk
$ wget http://www.coreseek.cn/uploads/csft/patch/Sphinx_1.11-dev_sphinxse_mysql-5.5.8.diff
$ wget http://www.coreseek.cn/uploads/csft/patch/Sphinx_1.11-r2652-dev_sphinxse_mysql-5.5.8.diff
$ tar xzvf mysql-5.5.8.tar.gz

#patch:
$ cd sphinx-trunk
$ patch -p0 < ../Sphinx_1.11-dev_sphinxse_mysql-5.5.8.diff
$ cp -R mysqlse ../mysql-5.5.8/storage/sphinx
$ rm mysqlse/CMakeLists.txt mysqlse/ha_sphinx.cc mysqlse/ha_sphinx.h
$ svn up -r 2652
$ patch -p0 < ../Sphinx_1.11-r2652-dev_sphinxse_mysql-5.5.8.diff
$ cp -R mysqlse ../mysql-5.5.8/storage/sphinx

#build:
$ cd ../mysql-5.5.8
$ cmake . -DCMAKE_BUILD_TYPE=Release -DWITH_SPHINX_STORAGE_ENGINE=1 #可能会提示CMAKE_BUILD_TYPE有问题,去掉略过
$ make
$ make install
$ ls -l storage/sphinx/ha_sphinx.*
#you'll see ha_sphinx.so.
$ cp support-files/mysql.server /etc/init.d/mysqld
$ chmod 755 /etc/init.d/mysqld
$ bash scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/app/mysql/data/
$ /etc/init.d/mysqld start
如果出现: /etc/init.d/mysqld: line 256: my_print_defaults: command not found
Starting MySQLCouldn't find MySQL server (./bin/mysqld_safe[FAILED]
则修改 /etc/init.d/mysqld中或/etc/my.cnf中的basedir和datadir
$ ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql
#tip:
#now ,you can run "make install" to install mysql at /usr/local/mysql.
#or , you can copy ha_sphinx.so to the patch lib/plugin/ in your mysql install directory.

#install plugin:
#login mysql with user root
$ mysql
mysql>INSTALL PLUGIN sphinx SONAME "ha_sphinx.so"
mysql>SHOW ENGINES;
#you'll see SPHINX in the ENGINE list.

linux下mysql5.5.11编译安装笔记[转]

mysql 最新的版本5.5.11需要cmake编译安装,估计以后的版本也会采用这种方式,网上找了一些安装方法有些地方是错的,自己整理一份 所以特地记录一下安装步骤及过程,以供参考!

1,安装所需要系统库相关库文件
yum –y install gcc gcc-c++ gcc-g77 autoconf automake zlib* fiex* libxml*
ncurses-devel libmcrypt* libtool-ltdl-devel*
2,创建mysql安装目录
# mkdir -p /usr/local/webserver/mysql/
3,创建数据存放目录
# mkdir -p /data/mysql/
4,创建用户和用户组与赋予数据存放目录权限
# groupadd mysql
# useradd -g mysql mysql
# chown mysql.mysql -R /data/mysql/
5,安装cmake(mysql5.5以后是通过cmake来编译的)
# wget http://www.cmake.org/files/v2.8/cmake-2.8.4.tar.gz
# tar zxvf cmake-2.8.4.tar.gz
# cd cmake-2.8.4
#.configure
# make &amp;&amp; make install
6,下载解压mysql 5.5.11
wget http://mirrors.sohu.com/mysql/MySQL-5.5/mysql-5.5.11.tar.gz
[root@localhost down]# tar zxvf mysql-5.5.11.tar.gz
[root@localhost down]# cd mysql-5.5.11
7,编译mysql-5.5.11
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/webserver/mysql/
\-DMYSQL_DATADIR=/data/mysql
\-DMYSQL_UNIX_ADDR=/data/mysql/mysqld.sock
\-DWITH_INNOBASE_STORAGE_ENGINE=1
\-DENABLED_LOCAL_INFILE=1 \-DMYSQL_TCP_PORT=3306
\-DEXTRA_CHARSETS=all \-DDEFAULT_CHARSET=utf8
\-DDEFAULT_COLLATION=utf8-general_ci
\-DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock
\-DMYSQL_USER=mysql \-DWITH_DEBUG=0
[root@host mysql-5.5.11]# make
[root@host mysql-5.5.11]# make install
8,复制配置文件
[root@mysql-5.5.11]# cp support-files/my-medium.cnf /etc/my.cnf
[root@mysql-5.5.11]# cp support-files/mysql.server /etc/init.d/mysqld
[root@mysql-5.5.11]# chmod 755 /etc/init.d/mysqld
9,初始化数据库
bash scripts/mysql_install_db user=mysql basedir=
/usr/local/webserver/mysql datadir=/data/mysql/
10,启动mysql服务
[root@localhost mysql-5.5.11]# /etc/init.d/mysqld start
11,启动完成之后用ps -ef |grep mysql 命令查看是否启动
12,/usr/local/webserver/mysql/bin/mysql -u root -p
通过命令行登录管理MySQL服务器 初始密码为空
13,修改root密码
mysql>;use mysql ;
mysql>; update user set password=PASSWORD(“123456″) where user=‘root’;
mysql>; FLUSH PRIVILEGES;

sphinx+MySQL的安装使用 [转]

sphinx-0.9.8-rc2-chinese.zip可以去http://www.s135.com/read.php/360.htm下
unzip sphinx-0.9.8-rc2-chinese.zip
tar zxvf mmseg-0.7.3.tar.gz
cd mmseg-0.7.3/
./configure
make
make install
cd ../

tar zxvf mysql-5.1.26-rc.tar.gz

tar zxvf sphinx-0.9.8-rc2.tar.gz
cd sphinx-0.9.8-rc2/
patch -p1 < ../sphinx-0.98rc2.zhcn-support.patch
patch -p1 < ../fix-crash-in-excerpts.patch
cp -rf mysqlse ../mysql-5.1.26-rc/storage/sphinx
cd ../

cd mysql-5.1.26-rc/
sh BUILD/autorun.sh
./configure –with-plugins=sphinx –prefix=/usr/local/mysql1/ –enable-assembler –with-extra-charsets=complex –enable-thread-safe-client –with-big-tables –with-readline –with-ssl –with-embedded-server –enable-local-infile
make && make install
cd ../
检查下是否安装好sphinx    show engines; 有个sphinx引擎

cd sphinx-0.9.8-rc2/
CPPFLAGS=-I/usr/include/python2.4
LDFLAGS=-lpython2.4
./configure –prefix=/usr/local/sphinx –with-mysql=/usr/local/mysql1
make
make install
cd ../
cp /usr/local/sphinx/etc/sphinx.conf.dist /usr/local/sphinx/etc/sphinx.conf

进入mysql
mysql>source /usr/local/sphinx/etc/example.sql;
假如要插入中文的要在my.cnf中加default_character_set=utf8重启服务就可以了
set names utf8;显示出中文 有关字符集以后有一个专题

配置sphinx vim /usr/local/sphinx/etc/sphinx.conf
source src1
{
type                    = mysql

sql_host                = localhost
sql_user                = root
sql_pass                =123
sql_db                    = test
sql_port                = 3307    # optional, default is 3306
sql_sock                = /usr/local/mysql1/var/mysql.sock
sql_query_pre            = SET NAMES utf8
sql_query                = \
SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
FROM documents
sql_attr_uint            = group_id
sql_attr_timestamp        = date_added
sql_ranged_throttle    = 0
sql_query_info        = SELECT * FROM documents WHERE id=$id
}
index test1
{
source            = src1
path            = /usr/local/sphinx/var/data/test1
docinfo            = extern
mlock            = 0
morphology        = none
min_word_len        = 1
charset_type        = utf-8
charset_table = U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z,\
A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6,\
U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101,\
U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109,\
U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F,\
U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, \
U+0116->U+0117,U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D,\
U+011D,U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, \
U+0134->U+0135,U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, \
U+013C,U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, \
U+0143->U+0144,U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, \
U+014B,U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, \
U+0152->U+0153,U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159,\
U+0159,U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, \
U+0160->U+0161,U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, \
U+0167,U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, \
U+016E->U+016F,U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175,\
U+0175,U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, \
U+017B->U+017C,U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, \
U+0430..U+044F,U+05D0..U+05EA, U+0531..U+0556->U+0561..U+0586, U+0561..U+0587, \
U+0621..U+063A, U+01B9,U+01BF, U+0640..U+064A, U+0660..U+0669, U+066E, U+066F, \
U+0671..U+06D3, U+06F0..U+06FF,U+0904..U+0939, U+0958..U+095F, U+0960..U+0963, \
U+0966..U+096F, U+097B..U+097F,U+0985..U+09B9, U+09CE, U+09DC..U+09E3, U+09E6..U+09EF, \
U+0A05..U+0A39, U+0A59..U+0A5E,U+0A66..U+0A6F, U+0A85..U+0AB9, U+0AE0..U+0AE3, \
U+0AE6..U+0AEF, U+0B05..U+0B39,U+0B5C..U+0B61, U+0B66..U+0B6F, U+0B71, U+0B85..U+0BB9, \
U+0BE6..U+0BF2, U+0C05..U+0C39,U+0C66..U+0C6F, U+0C85..U+0CB9, U+0CDE..U+0CE3, \
U+0CE6..U+0CEF, U+0D05..U+0D39, U+0D60,U+0D61, U+0D66..U+0D6F, U+0D85..U+0DC6, \
U+1900..U+1938, U+1946..U+194F, U+A800..U+A805,U+A807..U+A822, U+0386->U+03B1, \
U+03AC->U+03B1, U+0388->U+03B5, U+03AD->U+03B5,U+0389->U+03B7, U+03AE->U+03B7, \
U+038A->U+03B9, U+0390->U+03B9, U+03AA->U+03B9,U+03AF->U+03B9, U+03CA->U+03B9, \
U+038C->U+03BF, U+03CC->U+03BF, U+038E->U+03C5,U+03AB->U+03C5, U+03B0->U+03C5, \
U+03CB->U+03C5, U+03CD->U+03C5, U+038F->U+03C9,U+03CE->U+03C9, U+03C2->U+03C3, \
U+0391..U+03A1->U+03B1..U+03C1,U+03A3..U+03A9->U+03C3..U+03C9, U+03B1..U+03C1, \
U+03C3..U+03C9, U+0E01..U+0E2E,U+0E30..U+0E3A, U+0E40..U+0E45, U+0E47, U+0E50..U+0E59, \
U+A000..U+A48F, U+4E00..U+9FBF,U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF, \
U+2F800..U+2FA1F, U+2E80..U+2EFF,U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF, \
U+3040..U+309F, U+30A0..U+30FF,U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF, \
U+3130..U+318F, U+A000..U+A48F,U+A490..U+A4CF

min_prefix_len    = 0
min_infix_len        = 1
ngram_len                = 1
ngram_chars = U+4E00..U+9FBF, U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF,\
U+2F800..U+2FA1F, U+2E80..U+2EFF, U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF,\
U+3040..U+309F, U+30A0..U+30FF, U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF,\
U+3130..U+318F, U+A000..U+A48F, U+A490..U+A4CF

html_strip                = 0

}

indexer
{
mem_limit            = 32M

}
searchd
{
port                = 3312

log                    = /usr/local/sphinx/var/log/searchd.log

query_log            = /usr/local/sphinx/var/log/query.log

read_timeout        = 5

max_children        = 30

pid_file            = /usr/local/sphinx/var/log/searchd.pid

max_matches            = 1000

seamless_rotate        = 1

preopen_indexes        = 0
unlink_old            = 1
}
Source部分配置项说明

#type 数据库类型,目前支持mysql与pgsql
#strip_html 是否去掉html标签
#sql_host 数据库主机地址
#sql_user 数据库用户名
#sql_pass 数据库密码
#sql_db   数据库名称
#sql_port 数据库采用的端口
#sql_query_pre 执行sql前要设置的字符集,用utf8必须SET NAMES utf8
#sql_query  全文检索要显示的内容,在这里尽可能不使用where或group by,将where与groupby的内容交给sphinx,由sphinx进行条件过滤与groupby效率会更高
#注意:select 出来的字段必须至少包括一个唯一主键(ARTICLESID)以及要全文检索的字段,你计划原本在where中要用到的字段也要select出来
#这里不用使用orderby
#sql_attr_开头的表示一些属性字段,你原计划要用在where,orderby,groupby中的字段要在这里定义
#根据我们原先的SQL:
#select * from eht_articles where title like ? and catalogid=? And edituserid=?  And addtime between ? and ? order by hits desc
#我们需要对catalogid,edituserid,addtime,hits进行属性定义(这四个字段也要在select的字段列表中),定义时不同的字段类型有不同的属性名称,具体可以见sphinx.conf.in中的说明

index部分配置项说明

#source 数据源名
#path   索引记录存放目录,如d:/sphinx/data/cgfinal,实际存放时会存放在d:/sphinx/data目录,然后创建多个cgfinal名称,不同扩展名的索引文件。
#其他的配置如min_word_len,charset_type,charset_table,ngrams_chars,ngram_len这些则是支持中文检索需要设置的内容。
#如果检索的不是中文,则charset_table,ngrams_chars,min_word_len就要设置不同的内容,具体官方网站的论坛中有很多,大家可以去搜索看看。

具体的参数设置可以参考http://www.sphinxsearch.com/doc.html#searching

创建索引
./usr/local/sphinx/bin/indexer test1

启动sphinx守护进程

./usr/local/sphinx/bin/searchd

CREATE TABLE `sphinx` (
`id` int(11) NOT NULL,
`weight` int(11) NOT NULL,
`query` varchar(255) NOT NULL,
`group_id` int(11) NOT NULL,
`group_id2` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
KEY `Query` (`Query`)
) ENGINE=SPHINX CONNECTION=’sphinx://localhost:3312/test1′;

select content,date_added from test.documents docs join sphinx on (docs.id=sphinx.id) where query=’one document;mode=any’;

假如原来的表更新以后这个搜索引擎就不能搜到新的数据,因为他的索引没有及时创建。假如想要得到更新后的数据,需要从创建索引开始

以上要对原来的mysql要重新编译安装很是麻烦,但它提供了sphinx引擎使用起来非常方便。在网上找了半天也没有找到这个引擎的插件,很是郁闷。

可以通过sphinx自己的搜索来查看结果

./usr/local/sphinx/bin/search test

能够搜出中文 就是显示是乱码