django+django-haystack+Whoosh(后期切换引擎为Elasticsearch+ik)+Jieba+mysql

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

1.前提准备

环境介绍

  • haystack是django的开源搜索框架,该框架支持Solr,Elasticsearch,Whoosh,_*_Xapian*搜索引擎,不用更改代码,直接切换引擎,减少代码量。

  • 搜索引擎使用Whoosh,这是一个由纯Python实现的全文搜索引擎,没有二进制文件等,比较小巧,配置比较简单,当然性能自然略低。whoosh和xapian的性能差距还是比较明显。索引和搜索的速度有近4倍的差距,在full cache情况下的性能差距更是达到了60倍。

  • 中文分词+,由于Whoosh自带的是英文分词,对中文的分词支持不是太好,故用jieba替换whoosh的分词组件。

  • Elasticsearch:开源的搜索引擎,本文版本为7.6.0

  • 其他:Python3.6.5, Django2.2

安装环境

pip3 install django==2.2 -i https://pypi.douban.com/simple
pip3 install whoosh  -i https://pypi.douban.com/simple
pip3 install django-haystack -i https://pypi.douban.com/simple
pip3 install jieba -i https://pypi.douban.com/simple
pip3 install pymysql -i https://pypi.douban.com/simple
pip3 install elasticsearch==7.6.0 -i https://pypi.douban.com/simple/

项目结构

 - Project
   - Project
     - settings.py
   - blog
     - models.py

表结构

models.py

from django.db import models


class UserInfo(models.Model):
    username = models.CharField(verbose_name='用户名', max_length=225)

    def __str__(self):
        return self.username


class Tag(models.Model):
    name = models.CharField(verbose_name='标签名称', max_length=225)

    def __str__(self):
        return self.name


class Article(models.Model):
    title = models.CharField(verbose_name='标题', max_length=225)
    content = models.CharField(verbose_name='内容', max_length=225)
    # 外键
    username = models.ForeignKey(verbose_name='用户', to='UserInfo', on_delete=models.DO_NOTHING)
    tag = models.ForeignKey(verbose_name='标签', to='Tag', on_delete=models.DO_NOTHING)

    def __str__(self):
        return self.title

图解

本文优势

集全网的django+django-haystack+Whoosh的总结,取其精华,去其糟粕,加入了新的注解。

如果你想你的es或者Whoosh集成到django上,那你来对地方了

django+django-haystack+Whoosh+Jieba+mysql

1. setting.py配置

# 数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'dj_ha',
        'USER': 'root',
        'PASSWORD': 'foobared',
        'HOST': '106.14.42.253',
        'PORT': '11111',
    }
}
# app
INSTALLED_APPS = [ 
          'haystack', 
]
# 本教程使用的是Whoosh,故配置如下
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
        'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
    },
}
# 自动更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# 设置每页显示的数目,默认为20,可以自己修改
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 8

2. 为表模型创建索引,search_indexes.py

1. 如果你想针对某个app,例如blog做全文检索,则必须在blog的目录下面,建立search_indexes.py文件,文件名不能修改,必须叫search_indexes.py

from haystack import indexes
from .models import Article


# ArticleIndex:固定写法 表名Index
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
    # 固定写法  document=True:haystack和搜索引擎,将给text字段分词,建立索引,使用此字段的内容作为索引进行检索
    # use_template=True,使用自己的模板,与document=True进行搭配,自定义检索字段模板(允许谁可以被全文检索,就是谁被建立索引)
    text = indexes.CharField(document=True, use_template=True)
    # 以下字段作为辅助数据,便于调用,最后也不知道怎么辅助,我注释了,也不影响搜索
    # title:写入引擎的字段名,model_attr='title':相对应的表模型字段名,
    title = indexes.CharField(model_attr='title')
    content = indexes.CharField(model_attr='content')
    username = indexes.CharField(model_attr='username')
    tag = indexes.CharField(model_attr='tag')

    def get_model(self):
        # 需要建立索引的模型
        return Article

    def index_queryset(self, using=None):
        """Used when the entire index for model is updated."""
        # 写入引擎的数据,必须返回queryset类型
        return self.get_model().objects.all()

3. 创建被检索的模板(允许谁可以全文检索)

这个数据模板的作用是对Article.title, Article.content,Article.username.username

这三个字段建立索引,当检索的时候会对这三个字段的内容,做全文检索匹配。

数据模板的路径为yourapp/templates/search/indexes/yourapp/note_text.txt,

例如本例子为blog/templates/search/indexes/blog/article_text.txt 文件名必须为要索引的小写模型类名_text.txt

{{ object.title }}
{{ object.content }}
{{ object.username.username }}

4. 路由

urls.py配置(用内置的视图,后期可以自定义,本文也有介绍)

# urls.py
from django.contrib import admin
from django.urls import path, include, re_path

urlpatterns = [
    path('admin/', admin.site.urls),
    # 配置的搜索路由,路由可以自定义,include('haystack.urls')固定
    re_path(r'^search/', include('haystack.urls')),
]

haystack.urls的内容(内置的,只是我拉出来,让你看一下,不需要进行修改)

from django.urls import path

from haystack.views import SearchView

urlpatterns = [path("", SearchView(), name="haystack_search")]

5.search.html

SearchView()视图函数默认使用的html模板为当前app目录下,

路径为app名称,/templates/search/search.html

所以需要在blog/templates/search/下添加search.html文件,内容为

search.html(原生)

<h2>Search</h2>
<style>
    span.highlighted {
        color: red;
    }
</style>
<!--高亮加载-->
{% load highlight %}

<form method="get" action=".">
    <table>
        <!-- 对象.as_table 生成表格,里边会自动成成input标签 -->
        {{ form.as_table }}

        {#        {{ form.title.label }}#}
        <tr>
            <td></td>
            <td>
                <input type="submit" value="Search">
            </td>
        </tr>
    </table>

    {% if query %}
        <h3>返回结果</h3>

        {% for result in page.object_list %}
            <!-- page.object_list:返回查询的一页数据 -->
            <!-- result:数据对象 -->
            <p>
                {#                <a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}</a>#}
                <a href="{{ result.object.get_absolute_url }}">{% highlight result.object.title with query %}</a>
            </p>
            <span>
                {% highlight result.object.content with query %}
                {#                {{ result.object.content }}#}
            </span>

        {% empty %}
            <p>没有查询到结果!!!</p>
        {% endfor %}


        <!-- 分页 -->
        {% if page.has_previous or page.has_next %}
            <div>
                {% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}?
                Previous{% if page.has_previous %}</a>{% endif %}
                |
                {% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}Next ?
                {% if page.has_next %}</a>{% endif %}
            </div>
        {% endif %}
    {% else %}
        {# Show some example queries to run, maybe query syntax, something else? #}
    {% endif %}
</form>

后端返回数据介绍

# print(context)
        """
        {
        'query': '刘',
        'form': <ModelSearchForm bound=True, valid=True, fields=(q;models)>,
        'page': <Page 1 of 1>,
        'paginator': <django.core.paginator.Paginator object at 0x0000017D7E0F3470>,
        'suggestion': None}
        """
# print(context.get('page').__dict__)
        """
        {
        'object_list': 
            [
            <SearchResult: blog.article (pk=6)>, 
            <SearchResult: blog.article (pk=8)>, 
            <SearchResult: blog.article (pk=1)>
        ], 
        'number': 1, 
        'paginator': <django.core.paginator.Paginator object at 0x00000257C11A65C0>
        }
        """

前端返回数据介绍

{% load highlight %}:高亮加载 内置的会省略搜到的内容,之前的内容
{% load my_filters_and_tags %}:自定义高亮
form.as_table:生成表格,里边会自动成成input标签
query:查询的参数
page.object_list:返回的查询一页数据
result:数据对象集
result.object:当前查询的数据对象
page.has_previous or page.has_next:分页

6. 高亮配置

# 7.高亮加载
<style>
    span.highlighted {
        color: red;
    }
</style>
            
# 1.使用默认值
{% highlight result.summary with query %}
# 案例
<a href="{{ result.object.get_absolute_url }}">
{% highlight result.object.title with query %}
</a>
            
# 2.这里我们为 {{ result.summary }}里所有的 {{ query }} 指定了一个<div></div>标签,并且将class设置为highlight_me_please,这样就可以自己通过CSS为{{ query }}添加高亮效果了,怎么样,是不是很科学呢
{% highlight result.summary with query html_tag "div" css_class "highlight_me_please" %}
 
# 3.这里可以限制最终{{ result.summary }}被高亮处理后的长度
{% highlight result.summary with query max_length 40 %}           

# 5.自定义使用(后面会介绍)
# 5.4格式
{% myhighlight <text_block> with <query> [css_class "class_name"] [html_tag "span"] [max_length 200] [start_head True] %}
# 5.2使用一
{% myhighlight result.object.content with query css_class "highlighted" html_tag "span" max_length 200 start_head True %}
# 5.3自定义二
{% myhighlight result.object.content with query css_class "highlighted" start_head True %}        

7.自定义

自定义返回内容

在app下新建一个文件名称search_views

# 重写SearchView,实现自定义内容
# blog/search_views.py
from haystack.views import SearchView
# 导入模块
from .models import *


class MySeachView(SearchView):
    def extra_context(self):  # 重载extra_context来添加额外的context内容
        context = super(MySeachView, self).extra_context()
        my_str = '111'
        context['my_str'] = my_str
        # print(context)
        return context

修改路由

from django.contrib import admin
from django.urls import path, include, re_path
from blog import search_views

urlpatterns = [
    path('admin/', admin.site.urls),
    # 原生的
    # re_path(r'^search/', include('haystack.urls')),
    # 自己的
    re_path(r'^search/', search_views.MySeachView(), name='haystack_search'),
]

前端使用

<div>
圆明园:{{ my_str }}
</div>

自定义search.html模板

1. 保证有一个from,get请求,input标签的name=q,value=Search,

<form method="get" action=".">
    <table>
<tr>
<th>
<label for="id_q">Search:</label>
</th>
<td>
<input type="search" name="q" value="不得不说" id="id_q">
</td>
</tr>
        <tr>
            <td>
                <input type="submit" value="Search">
            </td>
        </tr>
    </table>
</form>

自定义高亮显示(原生的会省略)

新建文件夹templatetags

添加blog/templatetags/my_filters_and_tags.py 文件和 blog/templatetags/highlighting.py 文件,

内容如下(源码分别位于haystack/templatetags/lighlight.py 和 haystack/utils/lighlighting.py 中):
my_filters_and_tags.py

# encoding: utf-8
from __future__ import absolute_import, division, print_function, unicode_literals
 
from django import template
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils import six
 
from haystack.utils import importlib
 
register = template.Library()
 
class HighlightNode(template.Node):
    def __init__(self, text_block, query, html_tag=None, css_class=None, max_length=None, start_head=None):
        self.text_block = template.Variable(text_block)
        self.query = template.Variable(query)
        self.html_tag = html_tag
        self.css_class = css_class
        self.max_length = max_length
        self.start_head = start_head
 
        if html_tag is not None:
            self.html_tag = template.Variable(html_tag)
 
        if css_class is not None:
            self.css_class = template.Variable(css_class)
 
        if max_length is not None:
            self.max_length = template.Variable(max_length)
 
        if start_head is not None:
            self.start_head = template.Variable(start_head)
 
    def render(self, context):
        text_block = self.text_block.resolve(context)
        query = self.query.resolve(context)
        kwargs = {}
 
        if self.html_tag is not None:
            kwargs['html_tag'] = self.html_tag.resolve(context)
 
        if self.css_class is not None:
            kwargs['css_class'] = self.css_class.resolve(context)
 
        if self.max_length is not None:
            kwargs['max_length'] = self.max_length.resolve(context)
 
        if self.start_head is not None:
            kwargs['start_head'] = self.start_head.resolve(context)
 
        # Handle a user-defined highlighting function.
        if hasattr(settings, 'HAYSTACK_CUSTOM_HIGHLIGHTER') and settings.HAYSTACK_CUSTOM_HIGHLIGHTER:
            # Do the import dance.
            try:
                path_bits = settings.HAYSTACK_CUSTOM_HIGHLIGHTER.split('.')
                highlighter_path, highlighter_classname = '.'.join(path_bits[:-1]), path_bits[-1]
                highlighter_module = importlib.import_module(highlighter_path)
                highlighter_class = getattr(highlighter_module, highlighter_classname)
            except (ImportError, AttributeError) as e:
                raise ImproperlyConfigured("The highlighter '%s' could not be imported: %s" % (settings.HAYSTACK_CUSTOM_HIGHLIGHTER, e))
        else:
            from .highlighting import Highlighter
            highlighter_class = Highlighter
 
        highlighter = highlighter_class(query, **kwargs)
        highlighted_text = highlighter.highlight(text_block)
        return highlighted_text
 
 
@register.tag
def myhighlight(parser, token):
    """
    Takes a block of text and highlights words from a provided query within that
    block of text. Optionally accepts arguments to provide the HTML tag to wrap
    highlighted word in, a CSS class to use with the tag and a maximum length of
    the blurb in characters.
    Syntax::
        {% highlight <text_block> with <query> [css_class "class_name"] [html_tag "span"] [max_length 200] %}
    Example::
        # Highlight summary with default behavior.
        {% highlight result.summary with request.query %}
        # Highlight summary but wrap highlighted words with a div and the
        # following CSS class.
        {% highlight result.summary with request.query html_tag "div" css_class "highlight_me_please" %}
        # Highlight summary but only show 40 characters.
        {% highlight result.summary with request.query max_length 40 %}
    """
    bits = token.split_contents()
    tag_name = bits[0]
 
    if not len(bits) % 2 == 0:
        raise template.TemplateSyntaxError(u"'%s' tag requires valid pairings arguments." % tag_name)
 
    text_block = bits[1]
 
    if len(bits) < 4:
        raise template.TemplateSyntaxError(u"'%s' tag requires an object and a query provided by 'with'." % tag_name)
 
    if bits[2] != 'with':
        raise template.TemplateSyntaxError(u"'%s' tag's second argument should be 'with'." % tag_name)
 
    query = bits[3]
 
    arg_bits = iter(bits[4:])
    kwargs = {}
 
    for bit in arg_bits:
        if bit == 'css_class':
            kwargs['css_class'] = six.next(arg_bits)
 
        if bit == 'html_tag':
            kwargs['html_tag'] = six.next(arg_bits)
 
        if bit == 'max_length':
            kwargs['max_length'] = six.next(arg_bits)
 
        if bit == 'start_head':
            kwargs['start_head'] = six.next(arg_bits)
 
    return HighlightNode(text_block, query, **kwargs)

highlighting.py

# encoding: utf-8
 
from __future__ import absolute_import, division, print_function, unicode_literals
 
from django.utils.html import strip_tags
 
 
class Highlighter(object):
    #默认值
    css_class = 'highlighted'
    html_tag = 'span'
    max_length = 200
    start_head = False
    text_block = ''
 
    def __init__(self, query, **kwargs):
        self.query = query
 
        if 'max_length' in kwargs:
            self.max_length = int(kwargs['max_length'])
 
        if 'html_tag' in kwargs:
            self.html_tag = kwargs['html_tag']
 
        if 'css_class' in kwargs:
            self.css_class = kwargs['css_class']
 
        if 'start_head' in kwargs:
            self.start_head = kwargs['start_head']
 
        self.query_words = set([word.lower() for word in self.query.split() if not word.startswith('-')])
 
    def highlight(self, text_block):
        self.text_block = strip_tags(text_block)
        highlight_locations = self.find_highlightable_words()
        start_offset, end_offset = self.find_window(highlight_locations)
        return self.render_html(highlight_locations, start_offset, end_offset)
 
    def find_highlightable_words(self):
        # Use a set so we only do this once per unique word.
        word_positions = {}
 
        # Pre-compute the length.
        end_offset = len(self.text_block)
        lower_text_block = self.text_block.lower()
 
        for word in self.query_words:
            if not word in word_positions:
                word_positions[word] = []
 
            start_offset = 0
 
            while start_offset < end_offset:
                next_offset = lower_text_block.find(word, start_offset, end_offset)
 
                # If we get a -1 out of find, it wasn't found. Bomb out and
                # start the next word.
                if next_offset == -1:
                    break
 
                word_positions[word].append(next_offset)
                start_offset = next_offset + len(word)
 
        return word_positions
 
    def find_window(self, highlight_locations):
        best_start = 0
        best_end = self.max_length
 
        # First, make sure we have words.
        if not len(highlight_locations):
            return (best_start, best_end)
 
        words_found = []
 
        # Next, make sure we found any words at all.
        for word, offset_list in highlight_locations.items():
            if len(offset_list):
                # Add all of the locations to the list.
                words_found.extend(offset_list)
 
        if not len(words_found):
            return (best_start, best_end)
 
        if len(words_found) == 1:
            return (words_found[0], words_found[0] + self.max_length)
 
        # Sort the list so it's in ascending order.
        words_found = sorted(words_found)
 
        # We now have a denormalized list of all positions were a word was
        # found. We'll iterate through and find the densest window we can by
        # counting the number of found offsets (-1 to fit in the window).
        highest_density = 0
 
        if words_found[:-1][0] > self.max_length:
            best_start = words_found[:-1][0]
            best_end = best_start + self.max_length
 
        for count, start in enumerate(words_found[:-1]):
            current_density = 1
 
            for end in words_found[count + 1:]:
                if end - start < self.max_length:
                    current_density += 1
                else:
                    current_density = 0
 
                # Only replace if we have a bigger (not equal density) so we
                # give deference to windows earlier in the document.
                if current_density > highest_density:
                    best_start = start
                    best_end = start + self.max_length
                    highest_density = current_density
 
        return (best_start, best_end)
 
    def render_html(self, highlight_locations=None, start_offset=None, end_offset=None):
        # Start by chopping the block down to the proper window.
        #text_block为内容,start_offset,end_offset分别为第一个匹配query开始和按长度截断位置
        text = self.text_block[start_offset:end_offset]
 
        # Invert highlight_locations to a location -> term list
        term_list = []
 
        for term, locations in highlight_locations.items():
            term_list += [(loc - start_offset, term) for loc in locations]
 
        loc_to_term = sorted(term_list)
 
        # Prepare the highlight template
        if self.css_class:
            hl_start = '<%s class="%s">' % (self.html_tag, self.css_class)
        else:
            hl_start = '<%s>' % (self.html_tag)
 
        hl_end = '</%s>' % self.html_tag
 
        # Copy the part from the start of the string to the first match,
        # and there replace the match with a highlighted version.
        #matched_so_far最终求得为text中最后一个匹配query的结尾
        highlighted_chunk = ""
        matched_so_far = 0
        prev = 0
        prev_str = ""
 
        for cur, cur_str in loc_to_term:
            # This can be in a different case than cur_str
            actual_term = text[cur:cur + len(cur_str)]
 
            # Handle incorrect highlight_locations by first checking for the term
            if actual_term.lower() == cur_str:
                if cur < prev + len(prev_str):
                    continue
 
                #分别添上每个query+其后面的一部分(下一个query的前一个位置)
                highlighted_chunk += text[prev + len(prev_str):cur] + hl_start + actual_term + hl_end
                prev = cur
                prev_str = cur_str
 
                # Keep track of how far we've copied so far, for the last step
                matched_so_far = cur + len(actual_term)
 
        # Don't forget the chunk after the last term
        #加上最后一个匹配的query后面的部分
        highlighted_chunk += text[matched_so_far:]
 
        #如果不要开头not start_head才加点
        if start_offset > 0 and not self.start_head:
            highlighted_chunk = '...%s' % highlighted_chunk
 
        if end_offset < len(self.text_block):
            highlighted_chunk = '%s...' % highlighted_chunk
 
        #可见到目前为止还不包含start_offset前面的,即第一个匹配的前面的部分(text_block[:start_offset]),如需展示(当start_head为True时)便加上
        if self.start_head:
            highlighted_chunk = self.text_block[:start_offset] + highlighted_chunk
        return highlighted_chunk

前端使用

<style>
    span.highlighted {
        color: red;
    }
</style>

{% load my_filters_and_tags %}



{% myhighlight result.object.content with query css_class "highlighted" html_tag "span" max_length 200 start_head True %}

8. 目前位置搜索已经完成,可以重建索引,同步数据,测试一下

python manage.py rebuild_index

9.jieba分词器配置

9.1先从python包中复制whoosh_backend.py到app中,并改名为whoosh_cn_backend.py

文件路径:site-packageshaystackackendswhoosh_backend.py

在这里插入图片描述

复制到的路径:

9.2 对whoosh_cn_backend.py做以下修改:

1、导入 ChineseAnalyze
from jieba.analyse import ChineseAnalyzer

2、替换schema_fields[field_class.index_fieldname] = TEXT(下的analyzer
analyzer=ChineseAnalyzer(),

9.3在django的配置文件中,修改搜索引擎

HAYSTACK_CONNECTIONS = {
    'default': {
        # 设置haystack的搜索引擎
        'ENGINE': 'blog.whoosh_cn_backend.WhooshEngine',
        # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
        # 设置索引文件的位置
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
    }
}

10 django+django-haystack+Elasticsearch7.5+ik+mysql

10.0 切换成es引擎,除了settings.py和把jieba换成ik,其他步骤跟上面的都一样

如果一开始,就是奔着es+ik来的,那步骤9 jieba分词器配置****不用看,直接从步骤8跳到这里来

10.1 安装es,ik

基于docker安装Elasticsearch+ElasticSearch-Head+IK分词器_的博客-优快云博客基于docker安装Elasticsearch+ElasticSearch-Head+IK分词器[这里是图片010]https://blog.youkuaiyun.com/qq_52385631/article/details/126567059?spm=1001.2014.3001.5501

10.2 使用ik重写es7.5引擎

10.2.1 新建elasticsearch_ik_backend.py(在自己的app下)

在 blog应用下新建名为elasticsearch7_ik_backend.py的文件,继承Elasticsearch7SearchBackend(后端) 和Elasticsearch7SearchEngine(搜索引擎) 并重写建立索引时的分词器设置

from haystack.backends.elasticsearch7_backend import Elasticsearch7SearchBackend, Elasticsearch7SearchEngine

"""
分析器主要有两种情况会被使用:
第一种是插入文档时,将text类型的字段做分词然后插入倒排索引,
第二种就是在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索

如果想要让 索引 和 查询 时使用不同的分词器,ElasticSearch也是能支持的,只需要在字段上加上search_analyzer参数

在索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的

在查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用ES预设的
"""

DEFAULT_FIELD_MAPPING = {
    "type": "text",
    "analyzer": "ik_max_word",
    # "analyzer": "ik_smart",
    "search_analyzer": "ik_smart"

}


class Elasticsearc7IkSearchBackend(Elasticsearch7SearchBackend):
    def __init__(self, *args, **kwargs):
        self.DEFAULT_SETTINGS['settings']['analysis']['analyzer']['ik_analyzer'] = {
            "type": "custom",
            "tokenizer": "ik_max_word",
            # "tokenizer": "ik_smart",
        }
        super(Elasticsearc7IkSearchBackend, self).__init__(*args, **kwargs)


class Elasticsearch7IkSearchEngine(Elasticsearch7SearchEngine):
    backend = Elasticsearc7IkSearchBackend

10.3 修改settings.py(切换成功)

# es 7.x配置
HAYSTACK_CONNECTIONS = {
    'default': {
        # 'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
        'ENGINE': 'blog.elasticsearch_ik_backend.Elasticsearch7IkSearchEngine',
        # 'URL': 'http://106.14.42.253:9200/',
        'URL': 'http://106.14.42.253:9200/',
        # elasticsearch建立的索引库的名称,一般使用项目名作为索引库
        'INDEX_NAME': 'elastic_new',
    },
}

10.4 重建索引,同步数据

python manage.py rebuild_index

10.5 补充

10.5.1 未成功切换成ik

haystack 原先加载的是**…envLibsite-packageshaystackackends文件夹下的elasticsearch7_backend.py**文件,打开即可看到 elasticsearch7 引擎的默认配置

若用上述方法建立出来的索引字段仍使用snowball 分词器,则将原先elasticsearch7_backend.py文件中的DEFAULT_FIELD_MAPPING也修改为 ik 分词器(或许是因为版本问题)

位置:D:py_virtualenvdj_haLibsite-packageshaystackackendselasticsearch7_backend.py

修改内容:

DEFAULT_FIELD_MAPPING = {
    "type": "text",
    "analyzer": "ik_max_word",
    "search_analyzer": "ik_smart",
}

10.5.2 es6版本加入ik,重写引擎

from haystack.backends.elasticsearch_backend import ElasticsearchSearchBackend
from haystack.backends.elasticsearch_backend import ElasticsearchSearchEngine
class IKSearchBackend(ElasticsearchSearchBackend):
    DEFAULT_ANALYZER = "ik_max_word" # 这里将 es 的 默认 analyzer 设置为 ik_max_word

    def __init__(self, connection_alias, **connection_options):
        super().__init__(connection_alias, **connection_options)

    def build_schema(self, fields):
        content_field_name, mapping = super(IKSearchBackend, self).build_schema(fields)
        for field_name, field_class in fields.items():
            field_mapping = mapping[field_class.index_fieldname]
            if field_mapping["type"] == "string" and field_class.indexed:
                if not hasattr(
                    field_class, "facet_for"
                ) and not field_class.field_type in ("ngram", "edge_ngram"):
                    field_mapping["analyzer"] = getattr(
                        field_class, "analyzer", self.DEFAULT_ANALYZER
                    )
            mapping.update({field_class.index_fieldname: field_mapping})
        return content_field_name, mapping


class IKSearchEngine(ElasticsearchSearchEngine):
    backend = IKSearchBackend

11.实时更新索原理:采用信号

配置

# 在django配置文件中,添加索引值,文章更新的时候,就会自动更新索引值
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

RealtimeSignalProcessor源码如下:

class RealtimeSignalProcessor(BaseSignalProcessor):
    """
    Allows for observing when saves/deletes fire & automatically updates the
    search engine appropriately.
    当 检索对象出现保存或者删除的时候更新索引值。
    """
    def setup(self):
        # Naive (listen to all model saves).
        models.signals.post_save.connect(self.handle_save)
        models.signals.post_delete.connect(self.handle_delete)
     
        # Efficient would be going through all backends & collecting all models
        # being used, then hooking up signals only for those.
    def teardown(self):
        # Naive (listen to all model saves).
        models.signals.post_save.disconnect(self.handle_save)
        models.signals.post_delete.disconnect(self.handle_delete)
        # Efficient would be going through all backends & collecting all models
        # being used, then disconnecting signals only for those.

本文借鉴

Django haystack实现全文搜索 - -零 - 博客园 (cnblogs.com)
(9条消息) django-haystack全文检索详细教程_AC_hell的博客-优快云博客
(9条消息) Django全文检索Haystack模块_NQ31的博客-优快云博客_django haystack
(9条消息) django+drf_haystack+elasticsearch_的博客-优快云博客

(5条消息) Haystack 使用 Elasticsearch 建立索引时 修改为中文分词器_SevenBerry的博客-优快云博客_elasticsearch 修改字段分词器

(5条消息) Elasticsearch中analyzer和search_analyzer的区别_chuixue24的博客-优快云博客

最后

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

小编已加密:aHR0cHM6Ly9kb2NzLnFxLmNvbS9kb2MvRFVrVm9aSGxQZUVsTlkwUnc==出于安全原因,我们把网站通过base64编码了,大家可以通过base64解码把网址获取下来。

Django 使用 Haystack 实现检索功能 全文检索和搜索引擎原理 搜索需求 当用户再搜索框中输入关键字后,我们要为用户提供相关的搜索结果 搜索实现 django 中是使用 icontains 去模糊匹配,但是底层会转换成 like 去查询 但是 like 关键字的效率很低,如果数据库中有百万计数据,那么 like 查询是很慢的 如果查询需要在多个字段中进行,使用 like 关键字也不是很方便 全文搜索方案 引入全文检索的方案来实现商品搜索 即在指定的任意字段中进行检索查询 全文检索需要配合搜索引擎来实现(elasticsearch、sol 阅读详情

相关推荐

django-haystack,具有全文搜索功能的 Python 库!

Python Django Haystack库是一款强大的全文搜索引擎,适用于各种类型的项目,包括电子商务网站、新闻网站、社交网站和企业内部系统等。通过简单的配置和灵活的API,开发者可以轻松地实现高效的全文搜索功能,包括关键词搜索、过滤器、排序等功能。该库与不同的搜索引擎(如Elasticsearch、Whoosh等)兼容,提供了丰富的搜索索引和视图类,使得开发者能够快速构建可靠的搜索系统,提升用户体验和数据检索效率。总而言之,Python Django Haystack库为开发者提供了一个强大而灵活的工

m0_67847535的博客 1428

django-haystack 配置详解过程

前言 django是python语言的一个web框架,功能强大。配合一些插件可为web网站很方便地添加搜索功能。 搜索引擎使用whoosh,是一个纯python实现的全文搜索引擎,小巧简单。 中文搜索需要进行中文分词,使用jieba。 直接在django项目中使用whoosh需要关注一些基础细节问题,而通过haystack这一搜索框架,可以方便地在django中直接添加搜索功能,无需关注索引建立、搜索解析等细节问题。 haystack支持多种搜索引擎,不仅仅是whoosh,使用solr、elastic se

Jimy_Fengqi 3526

haystack之1初识haystack

本文走马观花式的介绍了haystack,然后实现了一个简单的QA。从下一篇文章起,我将首先介绍haystack的几个典型应用,在那之后详细的分析haystack的设计思路。注意上面提供的代码并不能直接运行,这里只是抽出核心的部分用于说明pipline的构造。从上面的流程图可以看出haystack的设计非常的清晰明了。创作打卡挑战赛 [外链图片转存中…(img-9gLFJQEe-1737689518537)]赢取流量/现金/优快云周边激励大奖。赢取流量/现金/优快云周边激励大奖。

2401_89791684的博客 733

【django】新闻模块——Haystack介绍和安装配置与渲染搜索结果页面【31】

提示 Elasticsearch 的底层是开源库 Lucene。但是没法直接使⽤ Lucene,必须⾃⼰写代码去调⽤它的接⼝。 思考 我们如何对接 Elasticsearch服务端? 解决⽅案 Haystack 一、Haystack介绍和安装配置 1、Haystack介绍 a、Haystack 是在Django中对接搜索引擎的框架,搭建了⽤户和搜索引擎之间的沟通桥梁。 我们在Django中可以通过使⽤ Haystack 来调⽤ Elasticsearch 搜索引擎 b、Haystack 可以在不修改代码的情

python全栈 1125

全志 T527_Android13 编译 [ 避坑必看 ]

Swap 概念: Linux中Swap(即:交换分区),类似于Windows的虚拟内存,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。它的功能就是在内存不够的情况下,操作系统先把内存中暂时不用的数据,存到硬盘的交换空间,腾出内存来让别的程序运行。当输入编译命令make -j16 的时候,会有如下提示,这是官方建议通过减少编译线程来解决编译时消耗内存过大的问题。Android 13 系统的编译流程,编译一共分为两部分:内核编译与 Android 编译。

公众号:嵌入式分享 2113

实战分享:如何用本地替换和插桩调试搞定Kasada最新版x-kpsdk-cd环境检测

本文深入解析Kasada最新版x-kpsdk-cd环境检测机制,提供动态请求拦截、本地替换和函数插桩等实战调试策略。通过Proxy保护破解、关键函数断点调试和环境检测对抗方案,帮助逆向工程师有效应对从280位扩展到294位的加密数组挑战,实现高效补环境调试。

weixin_29251567的博客 572

Django内容搜索框功能-----Haystack框架、Jieba分词、Whoosh引擎

一、安装库 安装django-haystack、whoosh、jieba库 pip install django-haystack==2.7.0 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install whoosh pip install jieba ’ 二、配置 1、注册haystack settings.py中注册应用haystack: INSTALLED_APPS = [ 。。。 'haystack', ] ’ 2、配置框架的引

Nty268的博客 2105

地质建模师必备:用Petrel快速生成浅地层TST/TVT厚度图的5个关键步骤

本文详细解析了地质建模师如何利用Petrel平台,将二维浅地层SEG-Y数据高效转化为真实地层厚度图(TST)和真实垂直厚度图(TVT)。文章系统梳理了从数据规范化导入、坐标系统一、地质界面解释到厚度计算与成图的5个关键实战步骤,并强调了误差控制与工程应用,为海上风电等工程地质评估提供了完整解决方案。

weixin_29204205的博客 521

django 基于haystack 基于elasticsearch实现全文搜索

pass。

m0_73399600的博客 2045

PX4从放弃到精通(十九):串口驱动

文章目录前言一、创建进程二、编写驱动 前言 硬件: PIXHAWK4 USB转串口模块 软件: Ubuntu18.04 PX4 1.11.3固件 QGC地面站 串口助手 一、创建进程 参考:https://mbot1.blog.youkuaiyun.com/article/details/122587617 二、编写驱动 .........

超维空间科技的博客 4601

【DeepSeek开发入门】DeepSeek API 开发初体验

在人工智能蓬勃发展的时代,DeepSeek作为一款功能强大的AI大模型,为开发者提供了丰富的接口和便捷的开发体验。本文将基于DeepSeek的几个关键接口,带你快速入门,开启DeepSeek开发的探索之旅。通过本文,你已经初步了解了DeepSeek开发中几个重要接口的使用方法,包括列出模型、对话补全和查询余额接口,以及开发过程中的常见问题及解决办法。这是你踏入DeepSeek开发领域的第一步。在后续的学习中,你可以深入研究模型的参数调优,探索不同模型在各种场景下的应用,如利用模型实现更复杂的推理对话功能。

寻道AI,探索AI无限可能! 2764

Django-Haystack 全文检索(Django实现搜索功能)

Django-Haystack 全文检索(Django实现搜索功能) 本文转载自Django Haystack 全文检索与关键词高亮 在此之前我们使用了 Django 内置的一些方法实现了一个简单的搜索功能。但这个搜索功能实在过于简单,没有多大的实用性。对于一个搜索引擎来说,至少应该能够根据用户的搜索关键词对搜索结果进行排序以及高亮关键字。现在我们就来使用 django-haystack 实现...

qq_42269354的博客 2901

【Claude Code 实战】第十章:DevOps 与 CI/CD 集成 / 光子AI

本章摘要:探讨Claude Code在DevOps与CI/CD集成中的应用。DevOps作为现代软件工程核心,结合AI技术实现自动化全流程,从代码提交到生产部署。通过CALMS模型(文化、自动化、精益、度量、分享)解析DevOps理念,对比传统瀑布模式与DevOps模式差异,展示AI如何加速Dockerfile编写、CI/CD配置等任务。典型示例显示AI可将原本30-60分钟的手动配置缩短至1-2分钟,大幅提升DevOps效率。

AI天才研究院 369

django项目中如何使用全文检索框架haystack的安装、配置和使用

1. 搜索引擎和全文检索框架概述 2. 安装和配置 (1)pip install djang-haystack==2.5.1 # 安装全文检索框架 注意:此案例中django使用的1.8.2,所以django-haystack==2.5.1不会报错 (2)pip install whoosh # 安装whoosh搜索引擎 (3)注册全文检索框架 INSTALLED_APPS = ( ... "haystack", # 注册全文检索框架 ) (4)全文检索框架...

weixin_42289273的博客 1293

基于Simscape的双PID比例调速阀与比例溢流阀液压控制系统建模与仿真

本文提出了一种基于Simscape的双PID液压控制系统建模方法,通过比例调速阀和比例溢流阀实现液压缸速度与压力的解耦控制。系统采用Simscape Fluids物理建模,精确模拟液压元件非线性特性。文章详细介绍了液压被控对象建模过程,包括动力单元、比例阀组合建模、执行机构及传感器配置。同时设计了双PID控制器架构,分别控制速度环和压力环,并给出参数整定建议。该方法通过物理网络直接模拟流体流动和压力动态,相比传统传递函数法具有更高精度,为液压系统仿真提供了有效解决方案。

AI的内部世界的博客 285

Java 新纪元 — JDK 25 + Spring Boot 4 全栈实战(十九):微服务实战——Boot 4 + Spring Cloud 2026.x,构建高并发电商分布式系统

Component@Slf4j@Autowired// 白名单路径@Override// 白名单放行// 提取Token// 传递用户信息到下游服务.mutate().build();@Override// 最高优先级if (bearer!@Component技术点Boot 3 时代Boot 4 时代提升线程模型平台线程池(200线程上限)虚拟线程(百万级并发)50x+服务通信。

qq_17204557的博客 186

django搜索 关键字 全文检索haystack 搜索分词数据库

Django Haystack 简介 django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr、Elasticsearch、Whoosh、Xapian 等多种搜索引擎,配合中文自然语言处理库 jieba 分词,就可以为博客提供博客文章搜索系统。 安装必要依赖 Whoosh。Whoosh 是一个由纯 Python 实现的全文搜索引擎,没有二进制文件等...

hypon的博客 1121

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

django4做中文分词

在你的应用下创建 “templates/search/indexes/应用名称/”下创建“模型类名称_text.txt”文件(例如你的应用是 test test/templates/search/indexes/test/note_text.txt),全小写即可。备注:如果想对多个模型做检索,比如这里还有一个book的字段,就再创建一个 test/templates/search/indexes/test/book_text.txt 的文件,然后配置。如果纯接口这里应该是没有用的,但是我会报错。

weixin_39543108的博客 170

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Haystack

什么是Haystack Haystack是django的开源全文搜索框架(全文检索不同于特定字段的模糊查询,使用全文检索的效率更高 ),该框架支持Solr,Elasticsearch,Whoosh,**Xapian搜索引擎它是一个可插拔的后端(很像Django的数据库层),所以几乎你所有写的代码都可以在不同搜索引擎之间便捷切换 安装 pip install django-haystac...

weixin_30394333的博客 204

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Django之Haystack对接搜索引擎框架Elasticsearch

Haystack是在Django中对接搜索引擎的框架,搭建用户和搜索引擎之间的沟通桥梁。它提供了一种简化的方式来集成不同的搜索引擎,如Elasticsearch、Whoosh、Solr等。

积跬步,至千里。 1776

基于django-haystack的全文高级搜索查询

一、基于数据库的模糊查询 这是一种很不理想的查询方法,并且对数据库的压力很大,查询的效率低下,我一般不建议采用这种查询方式。 例如:想要查询models.py中MyNew类的字段(title)标题 代码如下 def search(request): keyword = request.GET.get("keyword") # 获取前端传回来的查询关键字 newList = MyNew.objects.filter(title__icontains=keyword) # MyNe

有你真好的博客 1267

Django 配置搜索引擎 haystack 与 搜索页面无法返回数据问题

Django 配置搜索引擎 haystack 与 搜索页面无法返回数据问题

吾爱的博客 927

django-haystack全文检索详细教程

前几天要用Django-haystack来实现搜索功能,网上一搜中文资源少之又少,虽说有官方文档,但相信对于我们这些英语差的同学来说要看懂真的是一件难事。特别是关于高级部分,特地找了个英语专业的来翻译,也没能看出个名堂来,专业性实在是太强了,导致完全看不懂。。。 但是,对于一些小站点的开发来说,下面我要给大家讲的完全足够用了,只不过有时候确实麻烦点。好了,言归正传。为了节约时间,简单设置部分从网

越努力越幸运—liupu 3万+

django haystack深入研究

django haystack深入研究 前言 evalshell.com风炫安全 是我自己开发的一个搜集全网安全领域知识库的一个垂直领域的网站,对于一个垂直搜索网站,我深知搜索准确度和速度的重要,所以经过一番调研之后我选择了haystack这个全文搜索扩展库。 但是我有着自定义的需求,所以对haystack进行了源码分析定制。 软件简介 Haystack 是 Django 框架的搜索扩展模块。Haystack 提供统一的 API 允许你使用不同的搜索后端,包括Solr,Elasticse...

风炫的博客 770

Django 教程之添加搜索Django Haystack 全文检索与关键词高亮

当前关于django-haystack的教程大多同质化,当然我的教程也是参考后实战出来的,这里我将补充说明haystack中有关page和page_obj的不同使用(推荐page_obj)和搜索关键字高亮的时候其他字显示... 需求 能够根据用户的搜索关键词对搜索结果进行排序(日期)以及高亮搜索关键字 安装依赖包 当前环境: windows10 64 python3 django 1.11 当前版本: django-haystack whoosh jieba django-haystack Hays

Johnny's Lab 1032
上一篇: Java简历与面试
下一篇: Java 全栈知识体系( PDF 可下载)
普通网友
博客等级 码龄4年 3126粉丝 192原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值