一、OSQA搭建

直接按照wiki:

根据自己的系统来选择安装。我用的ubuntu+python2.6+django1.3 (1.4能用,但是需要改很多地方)。安装过程可以参考wiki,解释得已经很详细。过程中出现nomodule之类的都easy_install就可以了。

Osqa下载之后要配几个地方

 settings_local.py.dist重命名成settings_local.py。settings_local.py需要修改的地方:

        DATABASES={        'default':{        'ENGINE':'django.db.backends.mysql',        'NAME':'osqa',        'USER':'root',        'PASSWORD':'root',        'HOST':'127.0.0.1',        'PORT':'3306',        }

 根据自己的设置填写

    APP_URL='http://127.0.0.1:8000'    LANGUAGE_CODE='cn'#汉化得已经很不错了    DJANGO_VERSION=1.3#填写自己的django版本    DISABLED_MODULES=['mysqlfulltext','books','recaptcha','project_badges']#trunk的默认用的是mysql全文索引,需要把这个加到diabledmodule!

如果用sphinx做全文搜索的话,追加

        SPHINX_API_VERSION=0x116#refertodjangosphinxdocumentation        SPHINX_SEARCH_INDICES=('search_question_index',)#atupleofindexnamesrememberabouta#commaafterthe        SPHINX_SERVER='localhost'        SPHINX_PORT=9312

并且在settings.py

        INSTALLED_APPS=[        'django.contrib.auth',        'django.contrib.contenttypes',        'django.contrib.sessions',        'django.contrib.sites',        'django.contrib.admin',        'django.contrib.humanize',        'django.contrib.sitemaps',        'django.contrib.markup',        'forum',        'djangosphinx',        ]

当然,要用sphinx就easy_install django-sphinx和sphinxsearch。

到此,基本配置都已完成,不管用apache还是简单的manage.pyrunserver的方式都可以启动,看到界面了。配置邮件可以参考:(注:原文未说明)

接下来,注意到添加感兴趣标签的时候,输入标签名点击添加就可以看到刚才的标签已经在上面了,可是刷新之后发现不见了。于是查看代码之后发现这句:

    froumviewscommands.py line 536    try:    t = Tag.objects.get(name=tag)    mt = MarkedTag(user=request.user, reason=reason, tag=t)    mt.save()    except :    pass

    就是说,如果该标签不存在在数据库,不是已有的标签,就会静静地pass,而前端还能显示能加到。

    osqa1.png
    官网也是这个样子……….这样的方式不太友好,在没有该标签的时候应该给用户一个友好提示…

二、Coreseek实现OSQA的搜索

1. 两个问题

1、Mysql全文索引不堪重用

2、搜索问题显示没有match的。即使输入的是某个标题的关键字也搜不到,最后几天便一直卡在这个问题上。

Google了N多,试了又试,无意间在settings.py所在的目录看到有个log文件夹。里面有个django.osqa.log文件Tail-fdjango.osqa.log,在页面发一个搜索请求,看到了它其实用的是mysql的全文索引。如果表里没有数据,则搜索不到问题。

后来终于在/home/osqa/osqaweb/log目录下的django.osqa.log文件中看到这句,这个表forum_mysqlftsindex就是用mysql做全文索引建的表,建个trigger在每次人问问题和回答问题,都会触发这个触发器,并且重新将该问题相关的全部内容都重新更新到索引表:
osqa2.png

接下来试试搜索问题 也能看到这样:

osqa3.png

所以,很明显,默认的用的是mysqlfulltext,搜索的时候也走的这条线。

在这之前,试图很多次开启sphinxfulltext模块的时候,settings等地方需要都改了,需要配的都配了,但是始终在sphinx的服务端没有看到任何请求过来,coreseek虽然是第一次使用,但是对sphinx已经用了很久,所以能肯定sphinx的server端肯定是没有问题的。在看到上面的log之后就确定是默认走的是mysql的全文索引,于是在disabledmodule里将mysqlfulltext加上。就试了试搜索,就看到如下的结果:

osqa4.png

应该走的是django的模糊匹配,我的keyword是 ask,它就到forum_node这个问题表中用like ‘%ask%’这样的模糊匹配去取数据。当然,直接去这里找当然能找到了,页面也能显示相应的问题了,但是like毕竟不是长久之计,本身也对MySQL数据库产生巨大的压力,也就是说,表forum_mysqlftsindex就是用mysql做全文索引建的表,那么现在咱们得废掉这个MySQL本身提供的全文索引,寻找一种更为有效的全文索引方式或解决方案。

2. 基于sphinx之上的Coreseek实现搜索

下面就考虑给osqa的搜索用sphinx实现。因为包含中文搜索,虽然sphinx可以通过设定编码和有效字符集支持中文,但是中文分词搞不定,就用coreseek来实现,coreseek整合了分词+搜索。
(1)第一步安装coreseek:http://www.coreseek.cn/
 coreseek官网稳定版是3.2.14,是基于sphinx0.9.9的。
安装过程也没什么,直接参照:

先安装分词模块mmseg,出现如下所示的结果就可以了:

$ /usr/local/mmseg3/bin/mmseg -d /usr/local/mmseg3/etc src/t1.txt

中文/x 分/x 词/x 测试/x

中国人/x 上海市/x
Word Splite took: 1 ms
(2 )第二步是csft

看到如下所示表示已经安装成功:

$ /usr/local/coreseek/bin/indexer -c /usr/local/coreseek/etc/sphinx-min.conf.dist

##以下为正常测试时的提示信息:

Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2010,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)
using config file '/usr/local/coreseek/etc/sphinx-min.conf.dist'...
total 0 reads, 0.000 sec, 0.0 kb/call avg, 0.0 msec/call avg
total 0 writes, 0.000 sec, 0.0 kb/call avg, 0.0 msec/call avg

(3) OSQA内Sphinx配置文件

接下来为我们的问题搜索写sphinx配置文件,我的配置文件如下:

    #源定义    sourcebase_source    {    type=mysql    sql_host=localhost    sql_user=root    sql_pass=root    sql_db=osqa    sql_port=3306    sql_query_pre=SETNAMESutf8    sql_query_pre=SETSESSIONquery_cache_type=OFF    sql_query_info_pre=SETNAMESutf8    sql_range_step=1000    sql_query=    }    #index定义    indexbase_index    {    path=    source=base_source#对应的source名称    docinfo=extern    mlock=0    morphology=none    min_word_len=1    html_strip=0    #中文分词配置,详情请查看:http://www.coreseek.cn/products-install/coreseek_mmseg/    charset_dictpath=/usr/local/mmseg3/etc/#BSD、Linux环境下设置,/符号结尾    #charset_dictpath=etc/#Windows环境下设置,/符号结尾,最好给出绝对路径,例如:C:/usr/local/coreseek/etc/...    charset_type=zh_cn.utf-8    ngram_len=0    }    sourcesearch_question_source:base_source    {    sql_query_range=selectmin(id),max(id)fromforum_node    sql_query=SELECTquestion.id,question.title,author.username,question.tagnames,question.body,    GROUP_CONCAT(answer.body)asanswer_bodiesFROMforum_nodeASquestion,forum_nodeASanswer,    auth_userASauthorWHEREanswer.parent_id=question.idANDquestion.author_id=author.id    Andquestion.id>=$startandquestion.idDATE_FORMAT(NOW(),'%Y-%m-%d')    }    indexsearch_question_index:base_index    {    source=search_question_source    path=/ROOT/sphinx/index/search_question    }    indexdelta_search_question_index:search_question_index    {    source=delta_search_question_source    path=/ROOT/sphinx/index/delta_search_question    }    #全局index定义    indexer    {    mem_limit=128M    }    #searchd服务定义    searchd    {    listen=9312    read_timeout=5    max_children=30    max_matches=1000    seamless_rotate=0    preopen_indexes=0    unlink_old=1    pid_file=/ROOT/sphinx/log/searchd_osqa.pid#请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...    log=/ROOT/sphinx/log/searchd_osqa.log#请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...    query_log=/ROOT/sphinx/log/query_osqa.log#请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...

可以放在任何文件夹下只要建索引的时候指定就好。比如我的是放在/ROOT/sphinx/conf/sphinx_osqa.conf,接下来建索引:

indexer -c /ROOT/sphinx/conf/sphinx_osqa.conf --all –rotate

Base_index的警告可以忽略,然后启动守护进程:

searchd –c /ROOT/sphinx/conf/sphinx_osqa.conf

到此,sphinx的服务端都已经弄好,守护进程searchd在9312端口等待客户端发query。可以简单测试一下

search –c /ROOT/sphinx/conf/sphinx_osqa.confkeywords

3. Sphinx服务端配置的几个问题

Sphinx服务端配置已经完成,虽然自从diable掉mysqlfulltext之后就可以搜到问题,但是用的是Like%keyword%形式的请求。我们现在需要改的有三处:
(1)在/forum/models/question.py
    在Question类加入

        search=SphinxSearch(        index='search_question_index',        mode='SPH_MATCH_ALL',        )

 自己根据需求配置,比如设置权重之类的。

 (2)加入sphinx search,引用

from djangosphinx.models import SphinxSearch

(3) QuestionManager类加入

queryset=Question.search.query(keywords)

将命中的id取出来存成list结构,比如,存到变量ids里,然后直接返回

return False,self.filter(id__in=ids)

这样就返回了命中的id的所有问题。当然这种in的方式如果ids的数据量小的时候还可以,大了之后也不行,所以,后续应该考虑分页的方式来呈现更多的结果。

当然,最终能在服务器端上看到已经有收到请求了,如下图所示:
osqa5.png
至此,之前搜到不到关键词/tag的问题成功解决。也就是说,咱们的StackOverflow的原型OSQA已经搭建完成,接下来,便是一系列修改完善优化的工作。

感谢技术知己之一罗勍:http://weibo.com/u/1909128871。(项目已终止,2012.07.17)。