混合搜索在各大网站如京东、淘宝都有应用,他们的原理都是什么呢?本博文将为你介绍它们的实现过程。

混合搜索的原理,用一句话来说就是:关键字id进行拼接。

混合搜索示例:

数据库设计:

视频方向:

1
2
3
4
5
6
7
8
9
10
11
12
class Direction(models.Model):
    weight = models.IntegerField(verbose_name='权重(按从大到小排列)', default=0)
    name = models.CharField(verbose_name='名称', max_length=32)
 
    classification = models.ManyToManyField('Classification')
 
    class Meta:
        db_table = 'Direction'
        verbose_name_plural = u'方向(视频方向)'
 
    def __str__(self):
        return self.name

 视频分类:

1
2
3
4
5
6
7
8
9
10
class Classification(models.Model):
    weight = models.IntegerField(verbose_name='权重(按从大到小排列)', default=0)
    name = models.CharField(verbose_name='名称', max_length=32)
 
    class Meta:
        db_table = 'Classification'
        verbose_name_plural = u'分类(视频分类)'
 
    def __str__(self):
        return self.name

  视频:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Video(models.Model):
 
    status_choice = (
        (0, u'下线'),
        (1, u'上线'),
    )
    level_choice = (
        (1, u'初级'),
        (2, u'中级'),
        (3, u'高级'),
    )
    status = models.IntegerField(verbose_name='状态', choices=status_choice, default=1)#可用于管理员的审核
    level = models.IntegerField(verbose_name='级别', choices=level_choice, default=1)
    classification = models.ForeignKey('Classification', null=True, blank=True)
 
    weight = models.IntegerField(verbose_name='权重(按从大到小排列)', default=0)
 
    title = models.CharField(verbose_name='标题', max_length=32)
    summary = models.CharField(verbose_name='简介', max_length=32)
    img = models.ImageField(verbose_name='图片', upload_to='./static/images/Video/')
    href = models.CharField(verbose_name='视频地址', max_length=256)
 
    create_date = models.DateTimeField(auto_now_add=True)
 
    class Meta:
        db_table = 'Video'
        verbose_name_plural = u'视频'
 
    def __str__(self):
        return self.title

  备注:

  • 视频方向Direction类和视频分类Classification多对多关系,即一个视频方向对应多个视频分类,一个视频分类也可以对应多个视频方向。——classification = models.ManyToManyField('Classification')
  • 视频分类Classification类和视频Video类是一对多关系,即一个视频分类对应多个视频
  • 视频Video类中level_choice 与视频也是一对多关系,这里为了简化表关系,直接使用choices=level_choice来代替

混合搜索url设计:

默认url:

http://127.0.0.1:8000/video-0-0-0.html,其中第一个数字代表视频方向,默认0代表全部方向;第二个数字代表视频分类,默认0代表全部分类;第三个数字代表视频等级,默认0代表全部等级。

每一个a标签默认的url:

  例如运维自动化:<a href="/video-1-0-0.html">运维自动化</a>,即视频方向的对应数字为1,视频分类和视频等级都为0,这样做的目的是为了将此url和用户当前url进行拼接,并跳转到新的url。

  选择运维自动化后的url:

  多选情况下的url:

前端html:

加载自定义simple_tag:

1
{% load xx %}

  注:

  • xx:名为xx的py文件,里面包含自定义函数,方便html中进行调用
  • 在app中创建templatetags文件夹,将xx.py文件放在templatetags文件夹下

关于自定义simple_tag的更多信息,详见下文。

css:

 css代码

设置css目的,当用户选择视频方向、视频分类、视频等级时,加深对应a标签。

选择区域html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<h3>选择:</h3>
<div>
    {% action_all current_url 1 %} :
    {% for item in direction_list %}
 
         {% action current_url item 1 %}
    {% endfor %}
</div>
<div>
    {% action_all current_url 2 %} :
    {% for item in class_list %}
 
        {% action current_url item 2 %}
    {% endfor %}
</div>
<div>
    {% action_all current_url 3 %} :
    {% for item in level_list %}
        {% action current_url item 3 %}
    {% endfor %}
</div>
<hr />

  该区域全部基于自定义simple_tag实现,详见下文。

视频显示区域html:

1
2
3
4
5
6
7
8
9
10
<h3>视频:</h3>
  <hr />
 
  {% for item in video_list %}
      <a class="item" href="{{ item.href }}">
          <img src="/{{ item.img }}">
          <p>{{ item.title }}</p>
          <p>{{ item.summary }}</p>
      </a>
  {% endfor %}

  循环显示符合条件的全部视频。

自定义simple_tag:

全部标签的生成:

我们希望,当用户选择全部标签时,url对应位置为0,即当用户三个选择都是全部时,url为:/video-0-0-0.html

以视频方向为例介绍:

对应位置html:

1
{% action_all current_url 1 %} :

  从上述html可看出,action_all为对应的函数,它接收两个参数:当前url(current_url)、当前位置(视频方向、视频分类、视频等级)。其中current_url是后台传入html的,详见下文后台views函数介绍。

action_all函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template  
from django.utils.safestring import mark_safe
 
@register.simple_tag  #注册simple_tag
def action_all(current_url,index):   #接收当前url和对应的位置参数
    """
    获取当前url,video-1-1-2.html
    :param current_url:
    :param item:
    :return:
    """
    url_part_list = current_url.split('-')   #根据“-”进行分割
    if index == 3:  #如果是视频等级
        if url_part_list[index] == "0.html":  #如果选择的是全部
            temp = "<a href='%s' class='active'>全部</a>"   #添加 “active”属性
        else:
            temp = "<a href='%s'>全部</a>"
 
        url_part_list[index] = "0.html"
    else:
        if url_part_list[index] == "0":  
            temp = "<a href='%s' class='active'>全部</a>"
        else:
            temp = "<a href='%s'>全部</a>"
 
        url_part_list[index] = "0"
 
 
    href = '-'.join(url_part_list)  #处理后的列表再拼接成url字符串
 
    temp = temp % (href,)  #生成对应的a标签
    return mark_safe(temp)  #返回原生html

 其它a标签:

  以视频方向为例介绍:

 对应位置html:

1
{% action current_url item 1 %}

从上述html可看出:action函数接收三个参数 当前url、当前标签对象、当前位置。

  action函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@register.simple_tag
def action(current_url, item,index):
    # videos-0-0-1.html
    # item: id name
    # video-   2   -0-0.html
    url_part_list = current_url.split('-')
 
    if index == 3:
        if str(item['id']) == url_part_list[3].split('.')[0]:  #如果当前标签被选中
             temp = "<a href='%s' class='active'>%s</a>"
        else:
            temp = "<a href='%s'>%s</a>"
 
        url_part_list[index] = str(item['id']) + '.html' #拼接对应位置的部分url
    else:
        if str(item['id']) == url_part_list[index]:
            temp = "<a href='%s' class='active'>%s</a>"
        else:
            temp = "<a href='%s'>%s</a>"
 
        url_part_list[index] = str(item['id'])
 
    ur_str = '-'.join(url_part_list)  #拼接整体url
    temp = temp %(ur_str, item['name']) #生成对应的a标签
    return mark_safe(temp)  #返回安全的html

  至此,所有选择标签生成完毕,能够根据用户选择动态生成url。

视频显示区域的前后端处理:

前端html:

1
2
3
4
5
6
7
{% for item in video_list %}
      <a class="item" href="{{ item.href }}">
          <img src="/{{ item.img }}">
          <p>{{ item.title }}</p>
          <p>{{ item.summary }}</p>
      </a>
  {% endfor %}

  循环显示所有符合条件的视频。

后端views函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def video(request,*args,**kwargs):
    print(kwargs)
    print(request.path)
    request_path = request.path  #当前请求的路径
 
    = {}  #从数据库获取视频时的filter条件字典
    q['status'= 1 #状态为审核通过的
 
    class_id = int(kwargs.get('classification_id')) #获取url中的视频分类id
 
    direction_list = models.Direction.objects.all().values('id','name'#从数据库中获取所有的视频方向(包括视频方向的id和name)
 
    if kwargs.get('direction_id'== '0':
        # 方向选择全部
        print('方向等于0')
        class_list = models.Classification.objects.all().values('id''name'#方向id=0,即获取所有的视频分类(包括视频分类的id和name)
        if kwargs.get('classification_id'== '0'#如果视频分类id也为0,即全部分类
            pass
        else:
            # 如果视频分类不是全部,过滤条件为视频分类id in [url中的视频分类id]
            q['classification_id__in'= [class_id,]
 
    else:
        print('方向不为0')
        # 方向选择某一个方向,
        # 如果分类是0
        if kwargs.get('classification_id'== '0':
            print('分类为0')
            obj = models.Direction.objects.get(id=int(kwargs.get('direction_id')))  #获取已选择的视频方向
            class_list = obj.classification.all().values('id''name')  #获取该方向的所有视频分类
            id_list = list(map(lambda x: x['id'], class_list)) #获取所有视频分类对应的视频分类id
 
            q['classification_id__in'= id_list #过滤条件为视频分类id in [该方向下的所有视频分类id]
        else:
#方向不为0,分类也不为0
            obj = models.Direction.objects.get(id=int(kwargs.get('direction_id')))
            class_list = obj.classification.all().values('id''name')
            id_list = list(map(lambda x:x['id'], class_list))
            q['classification_id__in'= [class_id,] #过滤条件为视频分类id in [已经选择的视频分类id]
            print('分类不为0')
            # 当前分类如果在获取的所有分类中,则方向下的所有相关分类显示
            # 当前分类如果不在获取的所有分类中,
            if int(kwargs.get('classification_id')) in id_list:
                pass
            else:
                print('不再,获取指定方向下的所有分类:选中的回到全部')
                url_part_list = request_path.split('-')
                url_part_list[2= '0'
                request_path = '-'.join(url_part_list)
 
    level_id = int(kwargs.get('level_id')) #视频等级id
    if level_id == 0:
        pass
    else:
        q['level'= level_id #过滤条件增加视频等级
 
    # models.Video.objects.filter(status=1)
    video_list = models.Video.objects.filter(**q).values('title','summary''img''href')
 
 
    # level_list = models.Video.level_choice
 
    ret = map(lambda x:{"id": x[0], 'name': x[1]}, models.Video.level_choice)#把视频等级转化为单个标签是字典格式,整体是列表格式
    level_list = list(ret)
    return render(request, 'video.html', {'direction_list': direction_list,
                                          'class_list': class_list,
                                          'level_list': level_list,
                                          'current_url': request_path,
                                          "video_list": video_list})

:以上就是混合搜索的前后端全过程

关于django 京东淘宝 混合搜索实现原理的更多相关文章

  1. 淘宝主搜索离线集群完成Hadoop 2

    淘宝搜索离线dump集群(hadoop&hbase)2013进行了几次重大升级,本文中将这些升级的详细过程.升级中所遇到的问题以及这些问题的解决方案分享给大家.至此,淘宝主搜索离线集群完全进入 ...

  2. Android之仿京东淘宝的自动无限轮播控件

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于Re ...

  3. Android高仿京东淘宝自动无限循环轮播控件的实现思路和过程

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的实现思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于 ...

  4. 后盾网lavarel视频项目---5、淘宝镜像cnpm的原理及如何使用

    后盾网lavarel视频项目---5.淘宝镜像cnpm的原理及如何使用 一.总结 一句话总结: 原理:把npm上面的所有软件copy过来 使用:npm install -g cnpm --regist ...

  5. 淘宝语音搜索的实现——html5

    作为一个专业的淘宝控,不知道从什么时候开始发现淘宝上居然还有语音搜索,好吧,因为好奇心作祟还是想一探究竟.不过我想仔细一点的人,都会发现在只有在webkit内核的浏览器上有,原因是它只支持webkit ...

  6. javascript实现 京东淘宝等商城的商品图片大图预览功能

    在京东和淘宝等购买东西的时候,我们会经常预览左侧商品展示图片,把鼠标放到原图,右侧就会有个大图显示出细节.本文将带领大家写一个这样简单的功能! 一.实现原理 当鼠标移入某一图片内部时,图片上部会出现一 ...

  7. Ajax跨域实现淘宝/百度搜索下拉提示效果

    最近学到Ajax,觉得自己对与前后端的数据交互有了一个基本的了解.下面是Ajax应用到淘宝/百度的搜索功能的一个简单的小实例,就是输入一个词,下拉框中自动显示匹配的内容:

  8. 浅谈android中只使用一个TextView实现高仿京东,淘宝各种倒计时

    今天给大家带来的是只使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.近期公司一直加班也没来得及时间去整理,今天难得歇息想把这个分享给大家.只求共同学习,以及自己兴许 ...

  9. javascript实现 京东淘宝等商城的商品图片大图预览功能(图片放大器)

      在京东和淘宝等购买东西的时候,我们会经常预览左侧商品展示图片,把鼠标放到原图,右侧就会有个大图显示出细节.本文将带领大家写一个这样简单的功能! 一.实现原理 当鼠标移入某一图片内部时,图片上部会出 ...

随机推荐

  1. $.extend()与$.fn.extend()

    jQuery.extend(object) 扩展jQuery对象本身.用来在jQuery命名空间上增加新函数.jQuery.fn.extend(object) 扩展 jQuery 元素集来提供新的方法 ...

  2. ① 设计模式的艺术-01.单例(Singleton)模式

    单例模式为何要出现 在工作过程中,发现所有可以使用单例模式的类都有一个共性,那就是这个类没有自己的状态,换句话说,这些类无论你实例化多少个,其实都是一样的. 如果我们不将这个类控制成单例的结构,应用中 ...

  3. ASP.Net中表单POST到其他页面的方法

    在ASP中,我们通常把表单提交到另外一个页面(接受数据页面).但是在ASP.NET中,服务端表单通常都是提交到本页面的,如果我设置 form1.action="test.aspx" ...

  4. NYOJ 1073 最大值 (模拟)

    题目链接 输入N个数,M次查询. 每次查询给出一个数x. 要求:每次查询输出前x个数中第i小的数.(i为第i次查询) 你可以假设M <= N,Xi <= Xi+1 <= Xi+2 & ...

  5. React Native DEMO for Android

    Demo1: 主要知识:navigator,fecth 地址:https://github.com/hongguangKim/ReactNativeDEMO1 Demo2: 主要知识:navigato ...

  6. 有关mysql的innodb_flush_log_at_trx_commit参数【转】

    一.参数解释 0:log buffer将每秒一次地写入log file中,并且log file的flush(刷到磁盘)操作同时进行.该模式下在事务提交的时候,不会主动触发写入磁盘的操作. 1:每次事务 ...

  7. Deep Learning基础--各个损失函数的总结与比较

    损失函数(loss function)是用来估量你模型的预测值f(x)与真实值Y的不一致程度,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就越好.损失函数是经验 ...

  8. BZOJ 1975: [Sdoi2010]魔法猪学院——K短路,A*

    传送门 http://www.lydsy.com/JudgeOnline/problem.php?id=1975 题意&简要做法 一张有向图,求出最多的互不相同的路径,满足路径长度之和\(\l ...

  9. 主机名/etc/hosts文件的作用

    1,/etc/hosts,主机名ip配置文件. # Do not remove the following line, or various programs # that require netwo ...

  10. error: expected expression before ‘struct

    Linux C/C++编程时常会遇到“error: expected expression before ‘struct’”错误,此错误一般是由未定义的宏(宏里套宏)或参量引起,导致编译器判断当前语句 ...