elasticsearch实现博客搜索

7

通过drf、drf-haystack、elasticsearch实现搜索

一、服务器中安装elasticsearch

es的启动需要java环境,所以我们先安装jdk

1、安装jdk

官网下载:jdk
在服务器/opt目录下新建个java文件夹,并修改权限

cd /opt
mkdir java
chmod java 777

将下载好的压缩包上传至服务器/opt/java目录下
解压

tar -zxvf jdk-8u202-linux-x64.tar.gz

配置环境变量

vi /etc/profile

将以下环境变量添加到文件下面

export JAVA_HOME=/opt/java/jdk1.8.0_202
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

重新加载配置文件

source /etc/profile

查看是否安装成功

java -version

2、安装elasticsearch

官网下载elasticsearch
将下载文件上传至服务器/opt目录下
解压文件

tar -zxvf elasticsearch-2.4.1.tar.gz

进入解压文件夹下的bin目录

cd /opt/elasticsearch-2.4.1/bin

看到elasticsearch启动文件

因为elasticsearch不能使用root用户启动,创建一个用户
创建用户

useradd user-es

创建所属组

chown user-es:user-es -R /opt/elasticsearch-2.4.1

切换用户

su user-es

进入启动文件目录

cd /opt/elasticsearch-2.4.1/bin

启动elasticsearch,后面加-d使用后台启动

./elasticsearch -d

没有报错即启动成功

3、django项目配置

安装以下依赖

djangorestframework==3.13.1
elasticsearch==2.4.1
django-haystack==3.1.1
drf-haystack==1.8.11

在项目setting.py文件添加haystack配置并添加app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',

    'blog', # 博客app
    'haystack',
]

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': 'http://127.0.0.1:9200/',  # 此处为elasticsearch运行的服务器ip地址,端口号固定为9200
        'INDEX_NAME': 'blogindex',  # 指定elasticsearch建立的索引库的名称
    }
}
# 添加此项,当数据库改变时,会自动更新索引,非常方便
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

在博客app编写模型文件model.py

class Blog(BaseModel):
    title = models.CharField('标题', max_length=50)
    content = models.TextField('博客内容')
    description = models.TextField('博客描述')
    created_time = indexes.DateTimeField(model_attr='created_time')

在blog文件夹下添加search_indexes.py,固定文件名称

from haystack import indexes
from .models import Blog


# 类名必须为需要检索的Model_name+Index,这里需要检索Blog,所以创建BlogIndex
class BlogIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    id = indexes.IntegerField(model_attr='id')
    title = indexes.CharField(model_attr='title')
    description = indexes.CharField(model_attr='description')
    created_time = indexes.DateTimeField(model_attr='created_time')

    # 设置模型
    def get_model(self):
        return Blog

    # 设置查询范围
    def index_queryset(self, using=None):
        return self.get_model().objects.all()

text=indexes.CharField ,指定了将模型类中的哪些字段建立索引,而use_template=True说明后续我们还要指定一个模板文件,告知具体是哪些字段
每个索引里面必须有且只能有一个字段为 document=True,这代表 django haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。注意,如果使用一个字段设置了document=True,则一般约定此字段名为text,这是在 SearchIndex 类里面一贯的命名,以防止后台混乱

在项目的“templates/search/indexes/应用名称/”下创建“模型类名称_text.txt”文件(例如 templates/search/indexes/blog/blog_text.txt),全小写即可。

{{ object.title}}
{{ object.content }}
{{ object.description }}

这样在使用text查询时将会从title、content、description三个中查询
修改settings.py中的模板路径

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates'),], # 修改此处,否则django找不到模板文件
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

在blog目录下编写serializers.py序列化文件

from rest_framework import serializers
from .models import Blog
from drf_haystack.serializers import HaystackSerializer
from .search_indexes import BlogIndex

class BlogIndexSerializer(HaystackSerializer):
    """
    Article索引结果数据序列化器
    """
    class Meta:
        index_classes = [BlogIndex]
        fields = ['id', 'title', 'description', 'created_time'] # 需要序列化的字段,如果在search_indexes.py中没有配置这些字段,将会序列化成null
        search_fields = ['text'] # 将使用text作为搜索字段

编写blog/views.py

from rest_framework import mixins
from .models import Blog
from . import serializers
from drf_haystack.generics import HaystackGenericAPIView

from rest_framework.pagination import PageNumberPagination
from django.core.paginator import InvalidPage

# 分页器
class MyPageNumberPagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'page_size'

    def paginate_queryset(self, queryset, request, view=None):
        """
        Paginate a queryset if required, either returning a
        page object, or `None` if pagination is not configured for this view.
        """
        page_size = self.get_page_size(request)
        if not page_size:
            return None

        paginator = self.django_paginator_class(queryset, page_size)
        page_number = self.get_page_number(request, paginator)

        try:
            self.page = paginator.page(page_number)
        except InvalidPage:
            # 当超出最大页码时返回最后一页数据
            self.page = paginator.page(paginator.num_pages)

        if paginator.num_pages > 1 and self.template is not None:
            # The browsable API should display pagination controls.
            self.display_page_controls = True

        self.request = request
        return list(self.page)

class BlogSearchView(mixins.ListModelMixin, HaystackGenericAPIView):
    """
    返回博客文章搜索列表
    """
    index_models = [Blog] # 索引模型类
    pagination_class = MyPageNumberPagination # 分页器
    serializer_class = serializers.BlogIndexSerializer # 序列化器

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

编写blog/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('search', views.BlogSearchView.as_view())
]

编写项目urls.py

from django.urls import path, include

urlpatterns = [
    path('api/blog/', include('blog.urls')),
]

创建数据库并迁移后,需要生成索引

python manage.py rebuild_index

启动项目,访问http://192.168.1.5:8000/api/blog/search?text=测试


上一篇 Windows下Celery不执行