设为首页 收藏本站
查看: 1167|回复: 0

[经验分享] 使用Solr快速实现Django的全文搜索[转]

[复制链接]

尚未签到

发表于 2015-11-12 09:23:40 | 显示全部楼层 |阅读模式
  

使用Solr快速实现Django的全文搜索。http://fzuslideblog.appspot.com/2010/03/25/django_solr_search.html原文地址
  Django本身并没有提供全文搜索的功能,而自己给Django添加全文搜索的功能选择也有很多,可以用Sphinx,Lucene,Xapian等等来做。这里我们选用基于Lucene的全文搜索服务器Solr来快速的搭建Django的全文搜索应用。
  需要用到的开源项目:
  Solr:http://lucene.apache.org/solr/ (Apache License)
  Django-solr-search: http://code.google.com/p/django-solr-search/( BSD L)
  Pymmseg-cpp: http://code.google.com/p/pymmseg-cpp/ (MIT L)
  Django-solr-search是用来连接Solr服务器的Django插件,Py mmseg-cpp是Python封装的mmseg中文分词模块。
  1.配置环境
  首先安装Solr, 下载下来直接解压,然后进入apache-solr-1.4.0/example下面,直接运行:
  java -jar start.jar
  然后查看http://localhost:8983/solr/,看到欢迎界面,一切ok。
  然后把Django-solr-search下载下来,可以选择直接setup,也可以直接把其中 的solango放入需要增加全文搜索的Project下面。
  然后修改settings.py,加入solango的app,如下:

  INSTALLED_APPS = {
            ...
            'solango',
            ...
        }
  

添加Solr的路径:
  SOLR_ROOT ='path/apache-solr-1.4.0/example/'
SOLR_SCHEMA_PATH = SOLR_ROOT + 'solr/conf/schema.xml'
SOLR_DATA_DIR = SOLR_ROOT + 'solr/data'
SOLR_DEFAULT_OPERATOR = 'or'
  最后在项目下运行命令:
  让django启动Solr服务器 python manage.py solr --start
  查看是否连接成功:
  python manage.py shell

  >>> import solango
>>> solango.connection.is_available()
        True
  显示True,环境就搭好了。
  
  2.定义Document模型
  先看我们需要全文搜索的model:

  class ElectronicComponent(models.Model):
    '''
    Electronic Components Products
    '''
    p_name = models.CharField(_('product name'),max_length=200,
            help_text=_("Example:可调式电容"))
    partno = models.CharField(_('part number'),max_length=200,
            help_text=_("Alphanumeric characters only (letters, digits and underscores)"))
    dc = models.CharField(_('date code'),max_length=10,default=' ',  
            help_text=_("digits and '+','-','/'only "))
    qty = models.IntegerField(_('quantity'),null=True,blank=True,
            help_text=_("digits only"))
    mfg = models.CharField(_('manufactory'),max_length=200,default=' ',
            help_text=_("manufactory"))
    pack = models.CharField(_('packaging'),max_length=20,default=' ',
            help_text=_("packaging"))
    desp = models.TextField(_('description'),default=' ',
            help_text=_("description"))
    date_update = models.DateTimeField(_('last update'), default=datetime.datetime.now)   
    special_attrib = models.ManyToManyField('BasicAttribValue')
    cate_ID = models.ForeignKey('ElecompCategory')
    u = models.ForeignKey(IcUser)
    def __unicode__(self):
        return self.partno
  
  根据上面的model,定义全文搜索的Document模型:

  from models import ElectronicComponent
import solango
class ElectronicComponentDocument(solango.SearchDocument):
    '''
    非IC全文搜索模型
    '''
    p_name = solango.fields.CharField(copy=True)
    partno = solango.fields.CharField(copy=True)
    mfg = solango.fields.CharField(copy=True)
    pack = solango.fields.CharField(copy=True)
    desp = solango.fields.CharField(copy=True)
    cate_ID = solango.fields.CharField(copy=True)
    user = solango.fields.CharField(copy=True)
    def transform_user(self, instance):
        return instance.u
solango.register(ElectronicComponent, ElectronicComponentDocument)
  
  根据原有的ElectronicComponent生成ElectronicComponentDocument全文搜索模型,后面transform_user函数返回自己想给user返回的值。
  3.建立索引
  定义好以上的模型后,就可以建立索引了,先查看一下刚才定义的fields:
  运行命令:python manage.py solr --fields
  

  ########## FIELDS ###########
  
  <field name="mfg" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="url" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="text" type="text" indexed="true" stored="true" omitNorms="false" required="false" multiValued="true"/>
  <field name="site_id" type="integer" indexed="true" stored="true" omitNorms="false" required="true" multiValued="false"/>
  <field name="desp" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="partno" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="cate_ID" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="user" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="model" type="string" indexed="true" stored="true" omitNorms="false" required="true" multiValued="false"/>
  <field name="p_name" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  <field name="id" type="string" indexed="true" stored="true" omitNorms="false" required="true" multiValued="false"/>
  <field name="pack" type="string" indexed="true" stored="true" omitNorms="false" required="false" multiValued="false"/>
  
  ######## COPY FIELDS ########
  
  <copyField source="mfg" dest="text"/>
  <copyField source="desp" dest="text"/>
  <copyField source="partno" dest="text"/>
  <copyField source="cate_ID" dest="text"/>
  <copyField source="user" dest="text"/>
  <copyField source="p_name" dest="text"/>
  <copyField source="pack" dest="text"/>
  
  
  以上就是刚才模型中定义的Fields,如果以前已经有旧的索引存在了,就先运行:
  python manage.py solr –-flush
  把旧索引清空。然后根据我们定义的Document模型同步Schema.xml:
  
  python manage.py solr --schema
  最后重新启动Solr就可建立索引:
  python manage.py solr --reindex
  
  4.查询与分词
  能够简便的实现facets查询,这也是选择Solr来做全文搜索服务器原因之一。
  对刚才建立的索引,做一个测试:

  In [1]: from solango import connection
In [2]: from solango.solr.query import Query
In [3]: q = Query({'facet.field': 'cate_ID'}, q='ad')
In [4]: r = connection.select(q)
In [5]: r.count
Out[5]: 25
In [6]: facet_dict = {}
In [7]: for facet in r.facets:
   ...:     facet_dict[facet.name] = []
   ...:     for value in facet.values:
   ...:         if value.count > 0:
   ...:             facet_dict[facet.name].append({'name': value.name, 'value': value.value, 'count': value.count})
   ...:            
   ...:            
In [8]: facet_dict
Out[8]:
{u'cate_ID': [{'count': 16,
               'name': u'/u6307/u793a/u706f',
               'value': u'/u6307/u793a/u706f'},
              {'count': 4,
               'name': u'/u5176/u4ed6/u4e94/u91d1/u3001/u5de5/u5177',
               'value': u'/u5176/u4ed6/u4e94/u91d1/u3001/u5de5/u5177'},
              {'count': 3,
               'name': u'/u5355/u7247/u673aMcu',
               'value': u'/u5355/u7247/u673aMCU'},
              {'count': 1,
               'name': u'/u5e72/u7c27/u7ba1',
               'value': u'/u5e72/u7c27/u7ba1'},
              {'count': 1,
               'name': u'/u793a/u6ce2/u5668',
               'value': u'/u793a/u6ce2/u5668'}],
u'model': [{'count': 25,
             'name': u'Electroniccomponent',
             'value': u'product__electroniccomponent'}]}
In [9]: for one in facet_dict['cate_ID']:
            print one['name'], one['count']
   ....:     
   ....:   
  
指示灯 16
其他五金、工具 4
单片机Mcu 3
干簧管 1
示波器 1
  
  上面给facet增加一个新的field:cate_ID(分类 ),以“ad”作为关键字来查询,可以看到共检索出25条数据,同时也得到了这些数据位于5种不同分类及分别的数量。
  利用facet进行查询,对于分类搜索提供了一个行之有效的解决方案。
  定义更多种类的Query来实现搜索,基本上就跟Django没有关系,完全看对Solr的操作了。
  至于分词,可以独立出来看,而且可以选择的方式方法很多,这里拿Pymmseg举个例子:
  

  >>> from pymmseg import mmseg
>>> mmseg.dict_load_defaults()
>>> text = '电子电路电阻电容'
>>> algor = mmseg.Algorithm(text)
>>> for tok in algor:
...     print '%s [%d..%d]' % (tok.text, tok.start, tok.end)
...
电子电路 [0..12]
电阻 [12..18]
电容 [18..24]
  
  5.模板显示与排序
  对于模板的显示,Django-solr-search也提供了简洁的方式,在定义Document模型的之后加入对应的模板,来看个官方的例子。
  在定义模型的时候指定Document对应的模板:

  class EntryDocument(solango.SearchDocument):
    ... Fields ...
  
    class Media:
        template = "coltrane/entry_document.html"
    ... Transforms ...
solango.register(Entry, EntryDocument)
  
  模板:

  <div class="searchdocument">
<h3>Entry: <a href="{{document.fields.url.value }}" >{{ document.fields.title.value }}</a> </h3>
<p>
{{ document.highlight|safe }}
</p>
<ul class="sublinks">
    <li>at {{ document.fields.date.value|date:"N j Y" }}</li>
    <li class="last"><a href="{{document.fields.url.value }}">permalink</a></li>
</ul>
</div>
  
  在其他的页面中使用render_html方法, 引用嵌入定义的Document模板

  {% for doc in paginator.results.documents %}
    {{doc.render_html|safe}}
{% endfor %}
  
  当然,你也可以像以前一样使用普通的方式渲染模板。
  后台代码:

  def solr_search(request):
    '''
    用solr进行全文搜索
    '''
    keywords = request.GET['q']
    q = Query({'facet.field': 'cate_ID'},q=keywords)
    r = solr_conn.select(q)
    facet_dict = {}
    for facet in r.facets:
        facet_dict[facet.name] = []
        for value in facet.values:
            if value.count > 0:
                facet_dict[facet.name].append({'name': value.name, 'value': value.value, 'count': value.count})
    return render_to_response('product/productlist_solr.html',
                {'documents': r.documents,
                 'cate_ID_dict': facet_dict['cate_ID'],
                 'keyword': keywords},
                context_instance=RequestContext(request))
  
  模板中引用:

  {% for cate_ID in cate_ID_dict %}
          <td><a href="/product/category/{{cate_ID.name}}.html">{{cate_ID.name}}({{cate_ID.count}})</a></td>
          {% endfor %}
{% autoescape off %}
      {% for one in documents %}
      <tr class="{% cycle row1,row2 %}">
          <td><input type="checkbox" name="checkone" value="{{one.id}}" /></td>
          <td align="left" class="iclist"><a href="/productmenu/{{one.id}}.html"><spanclass="partno">{{one.partno}}</span></a></td>
          <td>{{one.mfg}}</td>
          <td>{{one.desp}}</td>
          <td class="red"><a href="/inquire/ask_attach/?partno={{one.id}}">{% trans 'Inquiry' %}</a></td>
      </tr>
      {% endfor %}
{% endautoescape %}
  
  显示效果:

  
  
  排序其实都是通过Solr来控制的,在settings.py中加入下面代码来控制排序:


SEARCH_SORT_PARAMS = {
        "score desc": "Relevance",
        "date desc" : "Date" # Added date
}
  
  6.索引的更新
  索引的更新问题对于一个应用来说也至关重要。这里提供了两种基本的更新方法。
  ImmediateIndexer:
  这个是默认的即时更新,不需要任何设置。但是lucene的索引创建速度并不快,因此这种方法只适合在数据量比较小,数据写入和删除操作并不多的情况下使用。
  DBQueuedIndexer
  这个方法是通过在数据库中创建一张表,记录下来数据操作的队列,然后在指定的时间针对这个队列表里的数据进行更新操作。
  需要在settings.py加入:



SEARCH_INDEXER = "solango.indexing.DBQueuedIndexer"
  定时运行:
  python manage.py solr –index-queued
  回过头来再看一下Django使用Solr搜索的原理,并不复杂,就是一个完整的爬虫类:
  通过 urllib2对Solr服务器的url进行访问,再读取Solr返回的xml文本,对文本解析,封装,最后渲染模板。
  以上就是快速的给Django应用加入全文搜索的一个方法,主要还是Django-solr-search的使用。而这个插件应用背景也比较有趣,最初做给是给《华盛顿时报》的网站使用的,这家报纸从创建之初竟然连续20年从未实现过盈利。
  
  官方文档地址:http://www.screeley.com/djangosolr/index.html
  
  除了 Django-solr-search之外,还有很多第三方的全文搜索插件可以使用,例如Haystack 等等,有兴趣也不妨学习一下。
  
   
版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-138187-1-1.html 上篇帖子: Solr4.5.1+tomcat8.0安装配置 下篇帖子: Windows下面安装和配置Solr
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表