码迷,mamicode.com
首页 > 其他好文 > 详细

06 全文检索

时间:2018-07-21 21:24:41      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:hot   rom   tokenizer   action   英文   ber   执行   定义   代码   

商品列表页的视图处理函数:

技术分享图片
class ListView(View):
    def get(self,request,catagory_id,page):
        # 取出当前页的分类商品,商品的主页

        sort = request.GET.get("sort",default)

        if sort not in ("price", "hot"):
            sort = "default"

        try:
            catagory = GoodsCategory.objects.get(id=catagory_id)
        except GoodsCategory.DoesNotExist:
            return redirect(reverse("goods:index"))

        # 取出全部商品的分类
        catagorys = GoodsCategory.objects.all()

        # 获取新品推荐的连个商品
        new_skus = GoodsSKU.objects.filter(category=catagory).order_by("-create_time")[:2]

        # 根据当前的分类商品,取出所有的商品
        if sort == "price":
            goods_skus = GoodsSKU.objects.filter(category=catagory).order_by("price")
        elif sort == "hot":
            goods_skus = GoodsSKU.objects.filter(category=catagory).order_by("sales")
        else:
            goods_skus = GoodsSKU.objects.filter(category=catagory)

        # 获取购物车的数量
        cart_num = 0
        redis_con = get_redis_connection(default)
        if request.user.is_authenticated:
            cart = redis_con.hgetall(cart_%s % request.user.id)
            for count in cart.values():
                cart_num += int(count)


        # 把当前分类的全部商品分页处理
        paginator=Paginator(goods_skus,1)
        # 获取当前也的数据
        page = int(page)
        try:
            page_skus=paginator.page(page)
        except EmptyPage:
            page_skus = paginator.page(1)

        # 查看当前页面的总数
        num_pages = paginator.num_pages
        # 页面展示的页数

        # 如果页数超过5页 页数属于最后三页  页面总数 paginator.num_pages    paginator.num_pages - page < 3
        # 其他剩余情况

        # 如果页数小于5页,展示全部的页数
        if num_pages <= 5:
            page_list = range(1, num_pages + 1)
        # 如果页数超过5页 页数属于前三页 page<=3,战士前5页
        elif page <= 3:
            # 页数属于前三页, 页数展示前5页
            page_list = range(1, 6)
        elif num_pages - page < 3:
            # 页数属于最后三页
            page_list = range(num_pages - 4, num_pages + 1)
        else:
            page_list = range(page - 2, page + 3)

        context = {
            "catagory": catagory,
            "catagorys": catagorys,
            "page_skus": page_skus,
            "new_skus": new_skus,
            "page_list": page_list,
            sort: sort,
            cart_num: cart_num

        }

        return render(request, "list.html", context)
View Code

 

商品列表页的请求路径

    url(r"^list/(?P<category_id>\d+)/(?P<page>\d+)$", views.ListView.as_view(), name="list"),

商品列表页的html页面:

技术分享图片
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}天天生鲜-商品列表{% endblock %}

{% block body %}
    <div class="navbar_con">
        <div class="navbar clearfix">
            <div class="subnav_con fl">
                <h1>全部商品分类</h1>    
                <span></span>            
                <ul class="subnav">
                    {% for category in categorys %}
                    <li><a href="{% url ‘goods:list‘ category.id 1 %}" class="{{ category.logo }}">{{ category.name }}</a></li>
                    {% endfor %}
                </ul>
            </div>
            <ul class="navlist fl">
                <li><a href="">首页</a></li>
                <li class="interval">|</li>
                <li><a href="">手机生鲜</a></li>
                <li class="interval">|</li>
                <li><a href="">抽奖</a></li>
            </ul>
        </div>
    </div>

    <div class="breadcrumb">
        <a href="{% url ‘goods:index‘ %}">全部分类</a>
        <span>></span>
        <a href="{% url ‘goods:list‘ category.id 1 %}">新鲜水果</a>
    </div>

    <div class="main_wrap clearfix">
        <div class="l_wrap fl clearfix">
            <div class="new_goods">
                <h3>新品推荐</h3>
                <ul>
                    {% for sku in new_skus %}
                    <li>
                        <a href="{% url ‘goods:detail‘ sku.id %}"><img src="{{ sku.default_image.url }}"></a>
                        <h4><a href="{% url ‘goods:detail‘ sku.id %}">{{ sku.name }}</a></h4>
                        <div class="prize">¥{{ sku.price }}</div>
                    </li>
                    {% endfor %}
                </ul>
            </div>
        </div>

        <div class="r_wrap fr clearfix">
            <div class="sort_bar">
                <a href="{% url ‘goods:list‘ category.id 1 %}?sort=default" {% if sort == "default" %}class="active"{% endif %}>默认</a>
                <a href="{% url ‘goods:list‘ category.id 1 %}?sort=price" {% if sort == "price" %}class="active"{% endif %}>价格</a>
                <a href="{% url ‘goods:list‘ category.id 1 %}?sort=hot" {% if sort == "hot" %}class="active"{% endif %}>人气</a>
            </div>

            <ul class="goods_type_list clearfix">
                {% for sku in page_skus %}
                <li>
                    <a href="{% url ‘goods:detail‘ sku.id %}"><img src="{{ sku.default_image.url }}"></a>
                    <h4><a href="{% url ‘goods:detail‘ sku.id %}">{{ sku.name }}</a></h4>
                    <div class="operate">
                        <span class="prize">¥{{ sku.price }}</span>
                        <span class="unit">{{ sku.price }}/{{ sku.unit }}</span>
                        <a href="#" class="add_goods" title="加入购物车"></a>
                    </div>
                </li>
                {%  endfor %}
            </ul>

            <div class="pagenation">
                {%  if page_skus.has_previous %}
                <a href="{{ page_skus.previous_page_number }}">上一页</a>
                {% endif %}
                {%  for p in  page_list %}
                <a href="{% url ‘goods:list‘ category.id p %}?sort={{ sort }}" {% if p == page_skus.number %}class="active"{% endif %}>{{ p }}</a>
                {%  endfor %}
                {%  if page_skus.has_next %}
                <a href="{{ page_skus.next_page_number }}">下一页></a>
                {% endif %}
            </div>
        </div>
    </div>
{% endblock %}
View Code

全文检索

全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理。

  • haystack:全文检索的框架,支持whoosh、solr、Xapian、Elasticsearc四种全文检索引擎,点击查看官方网站
  • whoosh:纯Python编写的全文搜索引擎,虽然性能比不上sphinx、xapian、Elasticsearc等,但是无二进制包,程序不会莫名其妙的崩溃,对于小型的站点,whoosh已经足够使用,点击查看whoosh文档
  • jieba:一款免费的中文分词包,如果觉得不好用可以使用一些收费产品。

在虚拟环境中依次安装需要的包。

pip install django-haystack
pip install whoosh
pip install jieba

1 settings.py文件,安装应用haystack。

INSTALLED_APPS = (
    ...
    haystack,
)

技术分享图片

 

2 在settings.py文件中配置搜索引擎

# haystack搜索框架的配置
HAYSTACK_CONNECTIONS = {
    ‘default‘: {
        #使用whoosh引擎
        ‘ENGINE‘: ‘haystack.backends.whoosh_backend.WhooshEngine‘,
        #索引文件路径
        ‘PATH‘: os.path.join(BASE_DIR, ‘whoosh_index‘),
    }
}
#当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = ‘haystack.signals.RealtimeSignalProcessor‘

3 在goods应用目录下新建一个search_indexes.py(固定的)文件,在其中定义一个商品索引类(类名可以随便取)

因为要对goods应用建立搜索,所以,search_indexes.py要建立在它的下面

  技术分享图片

from haystack import indexes
from goods.models import GoodsSKU


class GoodsSKUIndex(indexes.SearchIndex, indexes.Indexable):
    """索引类, 告诉haystack在建立数据索引的时候使用"""
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        """把那个表建立索引"""
        return GoodsSKU

    def index_queryset(self, using=None):
        """对表中的那个字段建立索引"""
        return self.get_model().objects.all()

 

4 在templates下面新建目录search/indexes/goods/goodssku_text.txt

goods是和应用的名字对应上,而goodssku是和get_model中对象的名字(小写)对应上的

技术分享图片

# 执行建立索引的字段
{{ object.name }}
{{ object.title }}

  

5 使用命令生成索引文件。

python manage.py rebuild_index

 技术分享图片

多了下面的文件

 技术分享图片

全文检索的使用:

1在项目根级配置url。

import haystack.urls

url(r‘^search/‘, include(haystack.urls)),

 技术分享图片

2 表单搜索时设置表单内容如下:

这个就是把搜索框写成固定的格式,我这继承的是base.html:

下面的是原来的页面:

技术分享图片
修改后的代码:

<div class="search_con fl">
       <form action="/search/" method="get">
                <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
                <input type="submit" class="input_btn fr" name="" value="搜索">
         </form>
</div>

 

点击标题进行提交时,会通过haystack搜索数据。

全文检索结果:

搜索出结果后,haystack会把搜索出的结果传递给templates/search目录下的search.html,在templates/search目录下建立search.html:

技术分享图片

编写如下的代码,对查询的结果进行渲染

技术分享图片
{% extends ‘base.html‘ %}

{% load staticfiles %}

{% block title %}天天生鲜-搜索结果{% endblock %}

{% block search_bar %}
    <div class="search_bar clearfix">
        <a href="{% url ‘goods:index‘ %}" class="logo fl"><img src="{% static ‘images/logo.png‘ %}"></a>
        <div class="sub_page_name fl">|&nbsp;&nbsp;&nbsp;&nbsp;搜索结果</div>
        <div class="search_con fr">
            <form action="/search/" method="get">
            <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
            <input type="submit" class="input_btn fr" value="搜索">
            </form>
        </div>
    </div>
{% endblock %}

{% block body %}
    <div class="main_wrap clearfix">
        <ul class="goods_type_list clearfix">
        {% for result in page %}
            <li>
                <a href="{% url ‘goods:detail‘ result.object.id %}"><img src="{{ result.object.default_image.url }}"></a>
                <h4><a href="{% url ‘goods:detail‘ result.object.id %}">{{result.object.name}}</a></h4>
                <div class="operate">
                    <span class="prize">¥{{ result.object.price }}</span>
                    <span class="unit">{{ result.object.price }}/{{ result.object.unit }}</span>
                </div>
            </li>
        {% empty %}
            <p>没有找到您要查询的商品。</p>
        {% endfor %}
        </ul>

        {% if page.has_previous or page.has_next %}
        <div class="pagenation">
            {% if page.has_previous %}<a href="/search/?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}<上一页{% if page.has_previous %}</a>{% endif %}
            |
            {% if page.has_next %}<a href="/search/?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}下一页>{% if page.has_next %}</a>{% endif %}
        </div>
        {% endif %}
    </div>
{% endblock %}
View Code

 

   query:搜索关 page:当前page paginator:分paginator象,result.object.id中的object对应的是进行建立所以的表GoodsSKU

HAYSTACK_SEARCH_RESULTS_PER_PAGE每页显示数量

 在搜索框搜索草莓:

技术分享图片

 返回结果如下:

技术分享图片

 上面的whoosh只支持对英文的分词,对中文支持的不好,所以更改它分词的方式:

cd /home/python/.virtualenvs/django_py3/lib/python3.5//site-packages//haystack/backends/

在上面的目录中创建ChineseAnalyzer.py文件

技术分享图片

import jieba
from whoosh.analysis import Tokenizer, Token

class ChineseTokenizer(Tokenizer):
    def __call__(self, value, positions=False, chars=False,
                 keeporiginal=False, removestops=True,
                 start_pos=0, start_char=0, mode=‘‘, **kwargs):
        t = Token(positions, chars, removestops=removestops, mode=mode, **kwargs)
        seglist = jieba.cut(value, cut_all=True)
        for w in seglist:
            t.original = t.text = w
            t.boost = 1.0
            if positions:
                t.pos = start_pos + value.find(w)
            if chars:
                t.startchar = start_char + value.find(w)
                t.endchar = start_char + value.find(w) + len(w)
            yield t

def ChineseAnalyzer():
    return ChineseTokenizer()

复制whoosh_backend.py文件,改为如下名称:whoosh_cn_backend.py

打开复制出来的新文件,引入中文分析类,内部采用jieba分词

在里面添加以下代码:
from .ChineseAnalyzer import ChineseAnalyzer

更改词语分析类

查找
analyzer=StemmingAnalyzer()
改为
analyzer=ChineseAnalyzer()

 

更改配置信息:
技术分享图片
重新创建索引数据
python manage.py rebuild_index

  技术分享图片

 

 

06 全文检索

标签:hot   rom   tokenizer   action   英文   ber   执行   定义   代码   

原文地址:https://www.cnblogs.com/aaronthon/p/9347821.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!