PHP+MongoDB+Coreseek/Sphinx(xmlpipe2数据源)打造千万级搜索引擎 骑猪看日落 2022-08-22 01:24 115阅读 0赞 近几年来,Linux+Nginx+PHP+MongoDB(LNPM)的组合越来越火,甚至有取代Linux+Nginx/Apache+PHP+Mysql组合的趋势。原因是MongoDB强大,灵活,易扩展,更关键的易用。MongoDB不用事先设计好表结构,往里面插入什么都可以,而且管理方便。因此成为创业团队的首选数据库,更是移动互联网的一枝新秀。 然而MongoDB和关系型数据库也有很多相似之处,比如**全文索引不支持中文**。MongoDB在2.6版本中开始默认支持全文索引,一如既往的不支持伟大的Chinese,所以如果需要搜索功能,就要另辟蹊径。 Sphinx和Lucene是做搜索引擎的不错的选择。个人观点Lucene对Java的支持比较好,而Sphixn对PHP的支持较好,所以我选择了Sphinx。其实Sphinx对中文的支持也不是很好,因为Sphinx是根据空格来分词(适用与英文),根本不适用中文分词。幸好有人提供了基于Sphinx的支持中文的插件[Coreseek][]和Sphinx—for—chinese。 Coreseek有完整的文档,目前支持最新版的Sphinx,所以我选择Coreseek。 Sphinx-for-chinese严重缺乏文档。 **安装:** [Coreseek安装。][Coreseek 1] [Sphinx-for-chinese安装。][Sphinx-for-chinese] **创建索引:** Coreseek支持与Mysql直接对接,只要在Coreseek配置文件里填上Mysql的信息,Coreseek就会自动读取Mysql数据来创建索引(当然前提是你做了生成索引的相应设置或执行生成索引的命令)。**然而Sphinx不支持与MongoDB直接对接,可以把Mongo数据源转换为Python数据源或转换成xmlpipe2数据源**。 本人不会Python,所以用php些了一个xml管道用于把MongoDB数据传输到Coreseek。 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> <div> 20 </div> <div> 21 </div> <div> 22 </div> <div> 23 </div> <div> 24 </div> <div> 25 </div> <div> 26 </div> <div> 27 </div> <div> 28 </div> <div> 29 </div> <div> 30 </div> <div> 31 </div> <div> 32 </div> <div> 33 </div> <div> 34 </div> <div> 35 </div> <div> 36 </div> <div> 37 </div> <div> 38 </div> <div> 39 </div> <div> 40 </div> <div> 41 </div> <div> 42 </div> <div> 43 </div> <div> 44 </div> <div> 45 </div> <div> 46 </div> <div> 47 </div> <div> 48 </div> <div> 49 </div> <div> 50 </div> <div> 51 </div> <div> 52 </div> <div> 53 </div> <div> 54 </div> <div> 55 </div> <div> 56 </div> <div> 57 </div> <div> 58 </div> <div> 59 </div> <div> 60 </div> <div> 61 </div> <div> 62 </div> <div> 63 </div> <div> 64 </div> <div> 65 </div> <div> 66 </div> <div> 67 </div> <div> 68 </div> <div> 69 </div> <div> 70 </div> <div> 71 </div> <div> 72 </div> <div> 73 </div> <div> 74 </div> <div> 75 </div> <div> 76 </div> <div> 77 </div> <div> 78 </div> <div> 79 </div> <div> 80 </div> <div> 81 </div> <div> 82 </div> <div> 83 </div> <div> 84 </div> <div> 85 </div> <div> 86 </div> <div> 87 </div> <div> 88 </div> <div> 89 </div> <div> 90 </div> <div> 91 </div> <div> 92 </div> <div> 93 </div> <div> 94 </div> <div> 95 </div> <div> 96 </div> <div> 97 </div> <div> 98 </div> <div> 99 </div> <div> 100 </div> <div> 101 </div> <div> 102 </div> <div> 103 </div> <div> 104 </div> <div> 105 </div> <div> 106 </div> <div> 107 </div> <div> 108 </div> <div> 109 </div> <div> 110 </div> <div> 111 </div> <div> 112 </div> <div> 113 </div> <div> 114 </div> <div> 115 </div> <div> 116 </div> </td> <td> <div> <div> <code><?php</code> </div> <div> </div> <div> <code>class</code> <code> SphinxXmlpipe{ </code> </div> <div> </div> <div> <code> </code> <code>private</code> <code>$xmlWriter</code> <code>;</code> </div> <div> <code> </code> <code>private</code> <code>$fields</code> <code>= </code> <code>array</code> <code>();</code> </div> <div> <code> </code> <code>private</code> <code>$attributes</code> <code>= </code> <code>array</code> <code>();</code> </div> <div> <code> </code> <code>private</code> <code>$documents</code> <code>= </code> <code>array</code> <code>();</code> </div> <div> </div> <div> <code> </code> <code>public</code> <code>function</code> <code>setFields(</code> <code>$fields</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->fields =</code> <code>$fields</code> <code>;</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>public</code> <code>function</code> <code>setAttributes(</code> <code>$attributes</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->attributes =</code> <code>$attributes</code> <code>;</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>public</code> <code>function</code> <code>beginOutput() { </code> </div> <div> <code> </code> <code>//create a new xml document</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter =</code> <code>new</code> <code>\XMLWriter();</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->openMemory();</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->setIndent(true);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->startDocument(</code> <code>'1.0'</code> <code>,</code> <code>'UTF-8'</code> <code>);</code> </div> <div> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->startElement(</code> <code>'sphinx:docset'</code> <code>);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->startElement(</code> <code>'sphinx:schema'</code> <code>);</code> </div> <div> </div> <div> <code> </code> <code>// add fileds to the schma</code> </div> <div> <code> </code> <code>foreach</code> <code>(</code> <code>$this</code> <code>->fields</code> <code>as</code> <code>$field</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->startElement(</code> <code>'sphinx:field'</code> <code>);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->writeAttribute(</code> <code>'name'</code> <code>,</code> <code>$field</code> <code>);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->endElement();</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>/*</code> </div> <div> <code> </code> <code>// add atttributes to the schema</code> </div> <div> <code> </code> <code>foreach($this->attributes as $attributes) { </code> </div> <div> <code> </code> <code>$this->xmlWriter->startElement('sphinx:attr');</code> </div> <div> <code> </code> <code>foreach($attributes as $key => $value) { </code> </div> <div> <code> </code> <code>$this->xmlWriter->writeAttribute($key, $value);</code> </div> <div> <code> </code> <code>}</code> </div> <div> <code> </code> <code>$this->xmlWriter->endElement();</code> </div> <div> <code> </code> <code>}</code> </div> <div> <code> </code> <code>*/</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->endElement();</code> <code>// schema</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>public</code> <code>function</code> <code>addDocument(</code> <code>$doc</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->startElement(</code> <code>'sphinx:document'</code> <code>);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->writeAttribute(</code> <code>'id'</code> <code>,</code> <code>$doc</code> <code>[</code> <code>'book_id'</code> <code>]);</code> </div> <div> </div> <div> <code> </code> <code>foreach</code> <code>(</code> <code>$doc</code> <code>as</code> <code>$key</code> <code>=> </code> <code>$value</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->startElement(</code> <code>$key</code> <code>);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->text(</code> <code>$value</code> <code>);</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->endElement();</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->endElement();</code> <code>// document</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>public</code> <code>function</code> <code>endOutput() { </code> </div> <div> <code> </code> <code>// end sphinx:docset</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->endElement();</code> </div> <div> <code> </code> <code>$this</code> <code>->xmlWriter->endDocument();</code> </div> <div> <code> </code> <code>echo</code> <code>$this</code> <code>->xmlWriter->outputMemory();</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>public</code> <code>function</code> <code>xmlpipe2() { </code> </div> <div> <code> </code> <code>$this</code> <code>->setfields(</code> <code>array</code> <code>(</code> </div> <div> <code> </code> <code>'book_id'</code> <code>,</code> </div> <div> <code> </code> <code>'book_name'</code> <code>,</code> </div> <div> <code> </code> <code>));</code> </div> <div> </div> <div> <code> </code> <code>$this</code> <code>->setAttributes(</code> <code>array</code> <code>(</code> </div> <div> <code> </code> <code>array</code> <code>(</code> </div> <div> <code> </code> <code>'name'</code> <code>=> </code> <code>'book_id'</code> <code>,</code> </div> <div> <code> </code> <code>'type'</code> <code>=> </code> <code>'int'</code> <code>,</code> </div> <div> <code> </code> <code>'bits'</code> <code>=> </code> <code>'16'</code> <code>,</code> </div> <div> <code> </code> <code>'default'</code> <code>=> </code> <code>'1'</code> <code>,</code> </div> <div> <code> </code> <code>),</code> </div> <div> <code> </code> <code>));</code> </div> <div> </div> <div> <code> </code> <code>$this</code> <code>->beginOutput();</code> </div> <div> </div> <div> <code> </code> <code>$mBook</code> <code>= D(</code> <code>'book'</code> <code>);</code> </div> <div> <code> </code> <code>$count</code> <code>= </code> <code>$mBook</code> <code>-></code> <code>count</code> <code>();</code> </div> <div> <code> </code> <code>$limit</code> <code>= c(</code> <code>'XMLPIPE_BOOKS_COUNT_PER_TIME'</code> <code>);</code> </div> <div> <code> </code> <code>$tCont</code> <code>= (int)</code> <code>$count</code> <code>/</code> <code>$limit</code> <code>;</code> </div> <div> <code> </code> <code>$oCount</code> <code>= </code> <code>$count</code> <code>%</code> <code>$limit</code> <code>;</code> </div> <div> <code> </code> <code>if</code> <code>(</code> <code>$tCont</code> <code>>0) { </code> </div> <div> <code> </code> <code>do</code> <code>{ </code> </div> <div> <code> </code> <code>$books</code> <code>= </code> <code>$mBook</code> <code>->field(</code> <code>'book_id,book_name'</code> <code>,</code> <code>'_id=>0'</code> <code>)->limit(</code> <code>$limit</code> <code>)->select();</code> </div> <div> <code> </code> <code>foreach</code> <code>(</code> <code>$books</code> <code>as</code> <code>$book</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->addDocument(</code> <code>$book</code> <code>);</code> </div> <div> <code> </code> <code>}</code> </div> <div> <code> </code> <code>unset(</code> <code>$books</code> <code>);</code> </div> <div> <code> </code> <code>$tCont</code> <code>--;</code> </div> <div> <code> </code> <code>}</code> <code>while</code> <code>(</code> <code>$tCont</code> <code>>0);</code> </div> <div> </div> <div> <code> </code> <code>$books</code> <code>= </code> <code>$mBook</code> <code>->field(</code> <code>'book_id,book_name'</code> <code>,</code> <code>'_id=>0'</code> <code>)->limit(</code> <code>$oCount</code> <code>)->select();</code> </div> <div> <code> </code> <code>foreach</code> <code>(</code> <code>$books</code> <code>as</code> <code>$book</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->addDocument(</code> <code>$book</code> <code>);</code> </div> <div> <code> </code> <code>}</code> </div> <div> <code> </code> <code>unset(</code> <code>$books</code> <code>);</code> </div> <div> <code> </code> <code>}</code> <code>else</code> <code>{ </code> </div> <div> <code> </code> <code>$books</code> <code>= </code> <code>$mBook</code> <code>->field(</code> <code>'book_id,book_name'</code> <code>,</code> <code>'_id=>0'</code> <code>)->limit(</code> <code>$oCount</code> <code>)->select();</code> </div> <div> <code> </code> <code>foreach</code> <code>(</code> <code>$books</code> <code>as</code> <code>$book</code> <code>) { </code> </div> <div> <code> </code> <code>$this</code> <code>->addDocument(</code> <code>$book</code> <code>);</code> </div> <div> <code> </code> <code>}</code> </div> <div> <code> </code> <code>unset(</code> <code>$books</code> <code>);</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code> </code> <code>$this</code> <code>->endOutput();</code> </div> <div> <code> </code> <code>}</code> </div> <div> </div> <div> <code>}</code> </div> </div> </td> </tr> </tbody> </table> 输出的xml格式如下 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> <div> 18 </div> <div> 19 </div> </td> <td> <div> <div> <code><</code> <code>document</code> <code>></code> </div> <div> <code><</code> <code>id</code> <code>>123</</code> <code>id</code> <code>></code> </div> <div> <code><</code> <code>group</code> <code>>45</</code> <code>group</code> <code>></code> </div> <div> <code><</code> <code>timestamp</code> <code>>1132223498</</code> <code>timestamp</code> <code>></code> </div> <div> <code><</code> <code>title</code> <code>>test title</</code> <code>title</code> <code>></code> </div> <div> <code><</code> <code>body</code> <code>></code> </div> <div> <code>this is my document body</code> </div> <div> <code></</code> <code>body</code> <code>></code> </div> <div> <code></</code> <code>document</code> <code>></code> </div> <div> </div> <div> <code><</code> <code>document</code> <code>></code> </div> <div> <code><</code> <code>id</code> <code>>124</</code> <code>id</code> <code>></code> </div> <div> <code><</code> <code>group</code> <code>>46</</code> <code>group</code> <code>></code> </div> <div> <code><</code> <code>timestamp</code> <code>>1132223498</</code> <code>timestamp</code> <code>></code> </div> <div> <code><</code> <code>title</code> <code>>another test</</code> <code>title</code> <code>></code> </div> <div> <code><</code> <code>body</code> <code>></code> </div> <div> <code>this is another document</code> </div> <div> <code></</code> <code>body</code> <code>></code> </div> <div> <code></</code> <code>document</code> <code>></code> </div> </div> </td> </tr> </tbody> </table> 相应的Coreseek设置 source src1 { type = xmlpipe2 xmlpipe_command = cd /var/www/PHPParser && php index.php /Home/SphinxXmlpipe/xmlpipe2 xmlpipe_field = book_id xmlpipe_field = book_name xmlpipe_attr_timestamp = book_id xmlpipe_attr_uint = book_id xmlpipe_fixup_utf8 = 1 } **搜索:** 1、PHP提供了Sphinx扩展,适用于Coreseek。 2、Sphinx 安装包提供了sphinxapi,在api目录下。 我用的PHP扩展 sphinx搜索代码示例 <table> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> <div> 12 </div> <div> 13 </div> <div> 14 </div> <div> 15 </div> <div> 16 </div> <div> 17 </div> </td> <td> <div> <div> <code>public</code> <code> function</code> <code>getResultBySearchText(</code> <code>$search_text</code> <code>) { </code> </div> <div> <code> </code> <code>$sphinxClient</code> <code>= </code> <code>new</code> <code>\SphinxClient();</code> </div> <div> <code> </code> <code>$sphinxClient</code> <code>->setServer(</code> <code>'localhost'</code> <code>, 9312); </code> <code>// server = localhost,port = 9312.</code> </div> <div> <code> </code> <code>$sphinxClient</code> <code>->setMatchMode(SPH_MATCH_ANY);</code> </div> <div> <code> </code> <code>$sphinxClient</code> <code>->setMaxQueryTime(5000); </code> <code>// set search time 5 seconds. </code> </div> <div> </div> <div> <code> </code> <code>$result</code> <code>= </code> <code>$sphinxClient</code> <code>->query(</code> <code>$search_text</code> <code>);</code> </div> <div> </div> <div> <code> </code> <code>if</code> <code>(isset(</code> <code>$result</code> <code>[</code> <code>'matches'</code> <code>])) { </code> </div> <div> <code> </code> <code>$rel</code> <code>[</code> <code>'time'</code> <code>] =</code> <code>$result</code> <code>[</code> <code>'time'</code> <code>];</code> </div> <div> <code> </code> <code>$rel</code> <code>[</code> <code>'matches'</code> <code>] =</code> <code>$result</code> <code>[</code> <code>'matches'</code> <code>];</code> </div> <div> <code> </code> <code>return</code> <code>$rel</code> <code>;</code> </div> <div> <code> </code> <code>}</code> <code>else</code> <code>{ </code> </div> <div> <code> </code> <code>$rel</code> <code>[</code> <code>'time'</code> <code>] =</code> <code>$result</code> <code>[</code> <code>'time'</code> <code>];</code> </div> <div> <code> </code> <code>return</code> <code>$rel</code> <code>;</code> </div> <div> <code> </code> <code>}</code> </div> <div> <code> </code> <code>}</code> </div> </div> </td> </tr> </tbody> </table> 由于用的xmlpipe数据源,所以返回的是文档id,还需要根据id去mongo提取数据。至于如何提取mongo数据,我就不写了,如果需要帮助就连系我吧(sq371426@163.com)。 [Coreseek]: http://www.coreseek.cn/ [Coreseek 1]: http://www.sundabao.com/ubuntu12-04-%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85sphinx-coreseek3-2-14%E5%8F%8Aphp-sphinx-%E6%89%A9%E5%B1%95%E5%BA%93/ [Sphinx-for-chinese]: http://www.sundabao.com/ubuntu12-04-%E5%AE%89%E8%A3%85-sphinx-for-chinese-%E5%85%A8%E6%96%87%E6%A3%80%E7%B4%A2%E5%BC%95%E6%93%8E/
还没有评论,来说两句吧...