Archive for 五月, 2010

MogileFS 安装配置


31 5月
官网:http://danga.com/mogilefs/ 与memcached一样,同为danga出品的一套分布式存储解决方案。貌似不少大网站有在用? mogilefs的文档貌似挺烂的,官网有一部分,Google code上的wiki有一部分(http://code.google.com/p/mogilefs/) 整理下我安装的过程,以备今后查看。 正版的安装文档应该是看这里:http://code.google.com/p/mogilefs/wiki/InstallHowTo (英文的而且有点乱- -) 首先下载3个东东,都必须要下:
  • http://search.cpan.org/dist/mogilefs-server/
  • http://search.cpan.org/dist/MogileFS-Utils/
  • http://search.cpan.org/dist/MogileFS-Client/
  • 或者通过svn checkout http://code.sixapart.com/svn/mogilefs/trunk (不推荐) 安装之前,先建立数据库: # mysql mysql> CREATE DATABASE mogilefs; mysql> GRANT ALL ON mogilefs.* TO 'mogile'@'%'; mysql> SET PASSWORD FOR 'mogile'@'%' = OLD_PASSWORD( 'sekrit' ); mysql> FLUSH PRIVILEGES; mysql> quit 然后就进入安装阶段,所有刚才下载的3个都需要安装,安装方法都一样,类似: # tar -xvf mogilefs-server-2.32.tar.gz # cd mogilefs-server-2.32 # perl Makefile.PL # make # make test # make install 这里是特别需要注意的,在perl Makefile.PL的时候,可能会提示缺少各种各样的perl包(至少我提示缺少了很多),这个时候,请到CPAN (http://cpan.org/)去搜索(可以直接到http://search.cpan.org/搜那些not found的模块),反正把你看到not found的警告中的关键字打进去搜,之后把搜到的模块下下来安装,安装方法和上面的一样。直到没有警告缺少任何东西为止。才可以继续make等后续动作,否则可能装好了也无法用哦。 ok,等你排除万难,把上面3个包需要的东西都装完,3个都无错安装完成后。用server的那个安装包里面的mogdbsetup这个方便的程序进行mysql db初始化,命令类似: # ./mogdbsetup --dbhost=mogiledb.yourdomain.com --dbname=mogilefs --dbuser=mogile --dbpassword=sekrit (详细可以看官方wiki中的Setup——Database Configuration) 之后就是配置Tracker,在你的每个tracker服务器上,新建一个文件/etc/mogilefs/mogilefsd.conf,注意是新建,不要试图和我一样去寻找,找不到这个东东的,目录自己开。注意读写权限。文件中写入类似: db_dsn = DBI:mysql:mogilefs:host=mogiledb.yourdomain.com;port=3306;mysql_connect_timeout=5 db_user = mogile db_pass = sekrit conf_port = 7001 listener_jobs = 5 node_timeout = 5 rebalance_ignore_missing = 1 (详细可以看wiki中的Tracker Configuration) 注意:这步完成后,就先要把tracker启动起来,安官网的说法mogilefsd不要去用root启动,所以: adduser mogile 接着: # su mogile $ mogilefsd -c /etc/mogilefs/mogilefsd.conf --daemon $ exit 如果想让tracker用memcached,可以这样: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:7001 settings set memcache_servers 127.0.0.1:10000 注意:mogadm这个命令必须tracker启了后才可以运行,其中--lib=/usr/local/share/perl/5.8.4是指定'MogileFS.pm'这个文件的位置,各人可能不同,自己搜下在哪儿,上面3个东东安装的时候应该也会显示的。 接下来是Storage Server Configuration,在你的每台storage server上新建一个存储用的目录,注意你等会用来启动mogstored的用户必须有这个目录的读写权限。 # mkdir /var/mogdata 配置,每台storage服务器新建一个配置文件/etc/mogilefs/mogstored.conf: httplisten=0.0.0.0:7500 mgmtlisten=0.0.0.0:7501 docroot=/var/mogdata 好,然后用'mogadm'把每个storage写到数据库中(注意事项和上面说的用memcached那里一样,另外记得防火墙不要把端口墙掉了): # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:7001 host add mogilestorage --ip=192.168.42.3 --port=7500 --status=alive 确认下是不是加进去了: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:7001 host list 后面的步骤可以直接看官网的,没什么花头,直接贴了: You also need to add devices for each storage host. If you don't provide a device id mogadm is supposed to do it for you... in practice I find it dies with an error, so you will need to manually add a unique device id after the host: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:7001 device add mogilestorage 1 Finally, add the correctly-name device (folder) to each storage host. I have been unable to get the tools to handle this well, so I am probably doing something wrong. As a workaround, I used the modadm device list command to see what device names were assigned and then I added the folders to my storage hosts. Run the following command: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:6001 device list It will list each host and the device name followed by its status and storage available. Here is example output: mogilestorage 1: alive used(G) free(G) total(G) dev1: alive 0.892 67.772 68.664 This means "mogilestorage" has a host id of "1" and it has one device named "dev1" on it and that device is in the "alive" state (your other statistics will probably be zeros). Using the example output above, you would simply create the directory on mogilestorage.yourdomain.com: # mkdir -p /var/mogdata/dev1 Finally, confirm that your devices are configured: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:7001 device list To get IO stats working, you need to install 'iostat'. Example for debian/ubuntu # apt-get install sysstat 好,现在可以启动storage server了,官网推荐是用root用户: # mogstored --daemon 如果一切成功的话: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:6001,192.168.42.2:7001 check 可以看到相应成功的信息。 暂时,至此,另外,之后应该就是对域名和mogilefs绑定的事情了,事先要准备类似 mogiledb.yourdomain.com, mogiletracker.yourdomain.com and mogilestorage.yourdomain.com 这样的3个域名,然后用: Create a domain # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:6001,192.168.42.2:7001 domain add testdomain Add a class to the domain: # mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:6001,192.168.42.2:7001 class add testdomain testclass 上面这些还没尝试过,暂时记录下。 平时正常启动的话: sudo -u mogile /usr/local/bin/mogilefsd -c /etc/mogilefs/mogilefsd.conf --daemon mogstored --daemon 就ok了。当然也可以直接写到/etc/rc.local里面自动启动。 另外,PHP调用的API也还没实验,详见http://pecl.php.net/package/mogilefs,有空实验后继续。 ——————————2010/6/1 PHP API 安装———————————— PHP的extension就从上面那个地址下就好了,版本是最新的,extension的出品网站是 http://projects.usrportage.de/index.fcgi/php-mogilefs 安装和文档分别是: Install documentation 安装的时候注意要先装neon的devel lib包,其他和普通的extension安装没区别。看安装的帮助就好,没什么难度。 应用示例:
    1. <?php
    2. $client = new MogileFs();
    3. $client->connect('host', 6001, 'myDomain');
    4.  
    5. $client->put('path/to/file', 'myFile', 'myClass');
    6. $metadata = $client->get('myFile');
    7.  
    8. $content = file_get_contents($metadata['path1']);
    9.  
    其中的host是指tracker的地址, 6001是tracker的端口, myDomain是类似:# mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:6001,192.168.42.2:7001 domain add testdomain 中加的testdomain myFile是文件的唯一key myClass是类似:# mogadm --lib=/usr/local/share/perl/5.8.4 --trackers=192.168.42.1:6001,192.168.42.2:7001 class add testdomain testclass 中的testclass 至此,最基本的mogileFs就ok了。其他一些待阅的详细东东,罗列下: FSCK(貌似是监控相关):http://code.google.com/p/mogilefs/wiki/FSCK Job Workers(可能是MogileFS中各种部件的角色工作分配): http://code.google.com/p/mogilefs/wiki/Jobs 其他的一些client:http://code.google.com/p/mogilefs/wiki/Clients 原理总览:http://code.google.com/p/mogilefs/wiki/HighLevelOverview

    SCWS中文分词


    20 5月
    因为在上一篇文章的末尾提到的,coreseek分词存在的问题,经过详细的测试,比较了原版sphinx和coreseek用同一种配置文件,都不分词索引的情况下,coreseek的速度仍然大幅度落后于原版sphinx,于是决定近期摒弃coreseek,换上原版的sphinx。但这样的话,coreseek提供的mmseg分词在搜索的时候也就无法继续使用了。(当然,除非你愿意2个都装,coreseek另外开端口只为分词服务- -) 基于这种情况,决定另外找一个分词的东东来支持搜索时的调用。使用传说中的Google搜了一下,基本锁定了几个分词的东东。 1. mmseg4j 同样是mmseg的算法,可惜是java版本的,功能上倒是比coreseek出品的那个mmseg要强大,新版本已经支持了max-word的分词方法,也就是“中华人民共和国”会被分成“中华人民 中华 人民 共和国 共和 国”类似这样的,可以说加大了搜索的智能性。 但可惜的是,对于我们这类纯php环境的朋友,要享受这个东东要付出的代价有点大。除了要整套java环境的支持,还要php-java-bridge这类方式的调用,无不让人望而止步啊。尝试了几个小时后,终于放弃抵抗,寻找其他方向去了。 mmseg4j对java的朋友可能会更有用吧,不过它的max-word分词强大程度还有待考量,我在linux下java调用测试的时候,结果也不是太满意,当然可能和词库有关吧,没有继续深究了。 2.ICTCLAS传说中的中科天玑出品,号称xx国际xx分词奖第一名,号称多少多少用户量,反正光环无数啦,虽然有共享版,但如果商用的话,似乎有不菲的费用。张宴自己搞的那套什么分词,也是基于这个东东的,尝试用他官网的demo测试一下,结果服务器链接错误 - -||| 怎么都感觉很有国企的风格啊。。。虽然似乎听起来算法不错,但想到我们最终还是要商用的,基本放弃。 3. SCWS,ftphp出品,ftphp貌似也是个搜索引擎,国人自己弄的?没太了解过反正。不过他的分词是开源的,号称自己是简易免费的分词,本来没抱什么太大希望其实,不过看他官方数据分词速度居然比楼上传说中的xx分词奖第一名的速度还要快。。。于是决定一试。 具体的文档可以参见官网(很详细很强大),下面我自己的一些心得,以备日后查看: 安装没什么花头,看doc的第一节照抄弄就行了,注意版本号换成最新的,然后因为我从来都是utf8的,所以所有gbk的地方替换掉,词库也只用了utf8的。值得注意的是,如果你和我一样要在php中调用的话,建议把php extension那段都做掉,起初我也偷懒想用php的exec去执行命令行就好了,结果比较下来,效率相差2个数量级。。。exec要上百毫秒,而extension只要几毫秒! 而最终xdebug分析下来,用extension的方式分词,比原来coreseek的mmseg也要快了1个数量级,笑~,估计近期就得和coreseek彻底说byebye了。 具体妙用大家自己看吧,maxwords也是支持的,感觉还不错,也可以另外加自己的词典,效率也很高,目前看来很完美。 ————————2010/5/31—————————————— 如果用txt自定义词库的话,第一次运行的时候,scws会自动把它编译成.xdb的格式,放到/tmp中去,也就是说,如果你的词典和我一样很大的话,而php的超时时间设定的又比较小的话,很有可能永远都无法生成出这个词典,也就是说,每次分词都会超时。 所以,建议大家第一次装好后,用命令行运行一下.txt的词库,类似: /usr/local/scws/bin/scws -c utf8 -r /usr/local/scws/etc/rules.utf8.ini -M 1 -i 中华人民共和国南京西路 -d /usr/local/scws/etc/dict.utf8.xdb:/usr/local/scws/etc/words.txt 之后:mv /tmp/scws-193b5b00.xdb /usr/local/scws/etc/ 以后用起来就是直接:  /usr/local/scws/bin/scws -c utf8 -r /usr/local/scws/etc/rules.utf8.ini -M 1 -i 中华人民共和国南京西路 -d /usr/local/scws/etc/dict.utf8.xdb:/usr/local/scws/etc/scws-193b5b00.xdb 这样就算第一次也不会很慢啦~

    Sphinx conf infix, Sphinx api total vs total found, quorum match vs extended2 mode


    14 5月
    最近公司使用sphinx中碰到的一些问题,做下记录。
    针对类似搜索“南京”时,无法搜出带有“南京西路”的数据问题的解决方案。
    第一步设置相应的.conf文件,修改如下属性:
    enable_star = 1 #开启传说中的wildcard syntax模式,详见手册9.2.19. enable_star
    min_infix_len  = 1 #设置最短匹配词长,详见手册9.2.16. min_infix_len
    infix_fields = estate_name,estate_address #要启用infix的字段,必须填!因为infix会加大开销,如果不填这个字段,会对所有字段做infix,那将是很恐怖的开销!详见手册9.2.18. infix_fields
    最后一个参数,手册上没有提到的,如果没有设置正确会对中文造成无解的属性:
    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
    额,不要惊慌,照抄就行了,把中文的都包括进去就ok了。
    完了后,停掉searchd,重建索引就好。
    之后,在搜索的时候,就可以使用类似'*南京*'、'*南京'、'南京*'之类的query,去当类似sql 的like用了,OVER。
    ——————————我是分割线———————————————— 当我们使用API从sphinx执行了一个查询之后,接口会返回一个数组。在这个数组中存在total_found和total两个值。 当查询出的结果数小于sphin中配置的最大返回结果数(默认为1000)时,这两个值是相等的。 而查询出的结果数大于sphin中配置的最大返回结果数(默认为1000)时,total_found的值是在sphinx中所有满足搜索条件的结果数,而total返回的是sphin中配置的最大返回值。 因此,在分页等需要所有满足搜索条件的结果数的时候,应该使用total_found的值。 ——————————我这个分割线又来了———————————— 在使用@(column1,column2,column3) "关键词1 关键词2 关键词3 关键词4 关键词5 ... 关键词N"/2这种参数的时候,搜索模式应该设置为SPH_MATCH_EXTENDED模式,而不能用传说中效率更高的SPH_MATCH_EXTENDED2模式,否则将会发生不可预料的事情。。。(沿用sphinx官方风格比喻,就是可能屏幕里面跳出来一只大猩猩,对着你仍酒桶。) END P.S. 很多其他sphinx的常见问题在官方FAQ中都有,比如filter中要用or的话,怎么解决,FAQ中就很牛叉。膜拜一下。 ————————————2010/5/18补充—————————————————— 发现上周提出的infix方式与现有分词索引的方式起了比较大的冲突(用了infix就基本无法用分词了),于是顺道回顾了一下张宴大师的博客,发现他原来早碰到过这个问题了。而他的解决方案明显非常不错。直接贴了: 1、一元分词和中文分词的结合:  ①、一元分词位于索引更新模块。Sphinx索引引擎对于CJK(中日韩)语言(必须是UTF-8编码)支持一元切分,假设【反恐行动是国产主视角射击网络游戏】这段文字,Sphinx会将其切成【反 恐 行 动 是 国 产 主 视 角 射 击 网 络 游 戏】,然后对每个字建立反向索引。如果用这句话中包含的字组成一个不存在的词语,例如【恐动】,也会被搜索到,所以搜索时,需要加引号,例如搜索【"反恐行动"】,就能完全匹配连在一起的四个字,不连续的【"恐动"】就不会被搜索到。但是,这样还有一个问题,搜索【"反恐行动游戏"】或【"国产网络游戏"】就会搜索不到。对于这个问题,采用位于搜索查询模块的中文分词来处理。 sphinx.conf配置文件中关于UTF-8中文一元分词的配置如下: ...省略... index t_source_main { source                  = t_source_main path                    = /data0/search/sphinx/data/t_source_main docinfo                 = extern mlock                   = 0 morphology              = none min_word_len            = 1 charset_type            = utf-8 min_prefix_len          = 0 html_strip              = 1 charset_table           = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F ngram_len               = 1 ngram_chars             = U+3000..U+2FA1F } ...省略... ②、中文分词位于搜索查询模块。搜索“反恐行动游戏”、“国产网络游戏”,先调用独立的中文分词系统,分别切分为“反恐行动 游戏”、“国产 网络游戏”,这时候,再给以空格分隔的词语加上引号,去Sphinx搜索【"反恐行动" "游戏"】或【"国产" "网络游戏"】,就能搜索到这条记录了。中文分词词库发生增、删、改,无需重建整个Sphinx搜索索引。 henry解释:也就是说,做索引的时候,不用词库去分词,而是沿用sphinx原来的一元分词法。在搜索的时候才用分词去做词组的完全匹配搜索。另外一个原因,用原版的一元分词索引速度也要快很多,在他的博文中提到:   “我的环境是10000转的SAS硬盘,如果换成15000转的硬盘,速度要更快,Sphinx官方给出的索建引速度为10Mbytes/秒。原版的sphinx一元分词创建索引速度在5.5M/秒以上,而打了LibMMSeg中文分词补丁的Sphinx创建索引速度只有300KB/秒,所以采用原版的sphinx 0.9.9能够保证频繁更新情况下的索引实时性。一元分词的索引的数据量会大一些,但可以通过sphinx分布式索引来解决搜索效率问题。”   希望对大家有所借鉴,原文地址http://blog.s135.com/sphinx_search/

    【转】.htaccess doc


    11 5月
    From: http://www.cccspace.net/b/htaccess.html 以下指命令的作用域都是.htaccess

    RewriteEngine On|Off

    RewriteEngine 可用On 或者 Off 打开或关闭rewrite功能。 rewrite configurations 不会继承,所以你得给每个你想用 rewrite功能的virtual host加上这个指令。 

    RewriteBase URL-path

    RewriteBase指令显式地设置了目录级重写的基准URL。在下文中,你可以看见RewriteRule可以用于目录级的配置文件中(.htaccess)并在局部范围内起作用,即规则实际处理的只是剥离了本地路径前缀的一部分。处理结束后,这个路径会被自动地附着回去。默认值是"RewriteBase physical-directory-path"。 在对一个新的URL进行替换时,此模块必须把这个URL重新注入到服务器处理中。为此,它必须知道其对应的URL前缀或者说URL基准。通常,此前缀就是对应的文件路径。但是,大多数网站URL不是直接对应于其物理文件路径的,因而一般不能做这样的假定! 所以在这种情况下,就必须用RewriteBase指令来指定正确的URL前缀。 如果你的网站服务器URL不是与物理文件路径直接对应的,而又需要使用RewriteBase指令,则必须在每个对应的.htaccess文件中指定RewriteRule 。  

    RewriteCond TestString CondPattern

    RewriteCond指令定义了一个规则的条件,即在一个RewriteRule指令之前有一个或多个RewriteCond指令。条件之后的重写规则仅在当前URI与pattern匹配并且符合这些条件的时候才会起作用。 Notice:All of these tests can also be prefixed by an exclamation mark ('!') to negate their meaning. 在正则表达式中,如果取反的话要用^,在这里需要用!号取反  

    RewriteOptions Options

    Sets some special options for the rewrite engine. 设定一些特殊的选项给rewrite. The Option string can be currently only one:inherit inherit 此值强制当前配置可以继承其父配置。 在虚拟主机级配置中,它意味着主服务器的映射表、条件和规则可以被继承。 在目录级配置中,它意味着其父目录的.htaccess中的条件和规则可以被继承。 MaxRedirects=number 为了避免目录级RewriteRule的无休止的内部重定向, 在此类重定向和500内部服务器错误次数达到一个最大值的时候, mod_rewrite会停止对此请求的处理。 如果你确实需要对每个请求允许大于10次的内部重定向,可以增大这个值。 This forces the current configuration to inherit the configuration of the parent. 强制当前的配置继承它parent的配置。 在per-virtual-server环境下,意味着maps, conditions , rules会被继承! 在per-directory 环境下 意味着它父目录的.htaccess配置中的conditions , rules 会被继承! 

    RewriteRule Pattern Substitution [flags]

    Text:
      .           任何单字符
      [chars]     Character class: One  of chars
      [^chars]    Character class: None of chars
      text1|text2 两者选一个: text1 or text2
    
    Quantifiers:量词
      ?           0 or 1 of the 前面的 text
      *           0 or N of the 前面的 text (N > 0)
      +           1 or N of the 前面的 text (N > 1)
    
    Grouping:
      (text)      Grouping of text
    
    可用$N来得到()中的内容:
     ( (a|b) | (c|d))
    $1 $2      $3  
    
    Anchors:
      ^           Start of line anchor
      $           End   of line anchor
    
    Escaping:
      \char       escape that particular char
                  (for instance to specify the chars ".[]()" etc.)
    
    注意:没有并且&
      ========================================================================================= flags
    1. 'redirect|R [=code]' (强制重定向 redirect)

      以http://thishost[:thisport]/(使新的URL成为一个URI) 为前缀的Substitution可以强制性执行一个外部重定向。 如果code没有指定,则产生一个HTTP响应代码302(临时性移动)。 如果需要使用在300-400范围内的其他响应代码,只需在此指定这个数值即可, 另外,还可以使用下列符号名称之一: temp (默认的), permanent, seeother. 用它可以把规范化的URL反馈给客户端,如, 重写``/~''为 ``/u/'',或对/u/user加上斜杠,等等。 注意: 在使用这个标记时,必须确保该替换字段是一个有效的URL! 否则,它会指向一个无效的位置! 并且要记住,此标记本身只是对URL加上 http://thishost[:thisport]/的前缀,重写操作仍然会继续。 通常,你会希望停止重写操作而立即重定向,则还需要使用'L'标记.
    2. 'forbidden|F' (强制URL为被禁止的 forbidden)

      强制当前URL为被禁止的,即,立即反馈一个HTTP响应代码403(被禁止的)。 使用这个标记,可以链接若干RewriteConds以有条件地阻塞某些URL。
    3. 'gone|G' (强制URL为已废弃的 gone)

      强制当前URL为已废弃的,即,立即反馈一个HTTP响应代码410(已废弃的)。 使用这个标记,可以标明页面已经被废弃而不存在了.
    4. 'proxy|P' (强制为代理 proxy)

      此标记使替换成分被内部地强制为代理请求,并立即(即, 重写规则处理立即中断)把处理移交给代理模块。 你必须确保此替换串是一个有效的(比如常见的以 http://hostname开头的)能够为Apache代理模块所处理的URI。 使用这个标记,可以把某些远程成分映射到本地服务器名称空间, 从而增强了ProxyPass指令的功能。 注意: 要使用这个功能,代理模块必须编译在Apache服务器中。 如果你不能确定,可以检查``httpd -l''的输出中是否有mod_proxy.c。 如果有,则mod_rewrite可以使用这个功能; 如果没有,则必须启用mod_proxy并重新编译``httpd''程序。
    5. 'last|L' (最后一个规则 last)

      立即停止重写操作,并不再应用其他重写规则。 它对应于Perl中的last命令或C语言中的break命令。 这个标记可以阻止当前已被重写的URL为其后继的规则所重写。 举例,使用它可以重写根路径的URL('/')为实际存在的URL, 比如, '/e/www/'.
    6. 'next|N' (重新执行 next round)

      重新执行重写操作(从第一个规则重新开始). 这时再次进行处理的URL已经不是原始的URL了,而是经最后一个重写规则处理的URL。 它对应于Perl中的next命令或C语言中的continue命令。 此标记可以重新开始重写操作,即, 立即回到循环的头部。但是要小心,不要制造死循环!
    7. 'chain|C' (与下一个规则相链接 chained)

      此标记使当前规则与下一个(其本身又可以与其后继规则相链接的, 并可以如此反复的)规则相链接。 它产生这样一个效果: 如果一个规则被匹配,通常会继续处理其后继规则, 即,这个标记不起作用;如果规则不能被匹配, 则其后继的链接的规则会被忽略。比如,在执行一个外部重定向时, 对一个目录级规则集,你可能需要删除``.www'' (此处不应该出现``.www''的)。
    8. 'type|T=MIME-type' (强制MIME类型 type)

      强制目标文件的MIME类型为MIME-type。 比如,它可以用于模拟mod_alias中的ScriptAlias指令, 以内部地强制被映射目录中的所有文件的MIME类型为``application/x-httpd-cgi''.
    9. 'nosubreq|NS' (仅用于不对内部子请求进行处理 no internal sub-request)

      在当前请求是一个内部子请求时,此标记强制重写引擎跳过该重写规则。 比如,在mod_include试图搜索可能的目录默认文件(index.xxx)时, Apache会内部地产生子请求。对子请求,它不一定有用的,而且如果整个规则集都起作用, 它甚至可能会引发错误。所以,可以用这个标记来排除某些规则。 根据你的需要遵循以下原则: 如果你使用了有CGI脚本的URL前缀,以强制它们由CGI脚本处理, 而对子请求处理的出错率(或者开销)很高,在这种情况下,可以使用这个标记。
    10. 'nocase|NC' (忽略大小写 no case)

      它使Pattern忽略大小写,即, 在Pattern与当前URL匹配时,'A-Z' 和'a-z'没有区别。
    11. 'qsappend|QSA' (追加请求串 query string append)

      此标记强制重写引擎在已有的替换串中追加一个请求串,而不是简单的替换。 如果需要通过重写规则在请求串中增加信息,就可以使用这个标记。
    12. 'noescape|NE' (在输出中不对URI作转义 no URI escaping)

      此标记阻止mod_rewrite对重写结果应用常规的URI转义规则。 一般情况下,特殊字符(如'%', '$', ';'等)会被转义为等值的十六进制编码。 此标记可以阻止这样的转义,以允许百分号等符号出现在输出中,如: RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE] 可以使'/foo/zed'转向到一个安全的请求'/bar?arg=P1=zed'.
    13. 'passthrough|PT' (移交给下一个处理器 pass through)

      此标记强制重写引擎将内部结构request_rec中的uri字段设置为 filename字段的值,它只是一个小修改,使之能对来自其他URI到文件名翻译器的 Alias,ScriptAlias, Redirect 等指令的输出进行后续处理。举一个能说明其含义的例子: 如果要通过mod_rewrite的重写引擎重写/abc为/def, 然后通过mod_alias使/def转变为/ghi,可以这样: RewriteRule ^/abc(.*) /def$1 [PT] Alias /def /ghi 如果省略了PT标记,虽然mod_rewrite运作正常, 即, 作为一个使用API的URI到文件名翻译器, 它可以重写uri=/abc/...为filename=/def/..., 但是,后续的mod_alias在试图作URI到文件名的翻译时,则会失效。 注意: 如果需要混合使用不同的包含URI到文件名翻译器的模块时, 就必须使用这个标记。混合使用mod_alias和mod_rewrite就是个典型的例子。
      For Apache hackers 如果当前Apache API除了URI到文件名hook之外,还有一个文件名到文件名的hook, 就不需要这个标记了! 但是,如果没有这样一个hook,则此标记是唯一的解决方案。 Apache Group讨论过这个问题,并在Apache 2.0 版本中会增加这样一个hook。
    14. 'skip|S=num' (跳过后继的规则 skip)

      此标记强制重写引擎跳过当前匹配规则后继的num个规则。 它可以实现一个伪if-then-else的构造: 最后一个规则是then从句,而被跳过的skip=N个规则是else从句. (它和'chain|C'标记是不同的!)
    15. 'env|E=VAR:VAL' (设置环境变量 environment variable)

      此标记使环境变量VAR的值为VAL, VAL可以包含可扩展的反向引用的正则表达式$N和%N。 此标记可以多次使用以设置多个变量。 这些变量可以在其后许多情况下被间接引用,但通常是在XSSI (via or CGI (如 $ENV{'VAR'})中, 也可以在后继的RewriteCond指令的pattern中通过%{ENV:VAR}作引用。 使用它可以从URL中剥离并记住一些信息。
    16. 'cookie|CO=NAME:VAL:domain[:lifetime[:path]]' (设置cookie)

      它在客户端浏览器上设置一个cookie。 cookie的名称是NAME,其值是VAL。 domain字段是该cookie的域,比如'.apache.org', 可选的lifetime是cookie生命期的分钟数, 可选的path是cookie的路径。

    貓熊寶寶幼齒園

    姜經緯的博客