利用elasticsearch实现搜索引擎

  ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是第二最流行的企业搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

起步

1. 安装jdk

  由于elasticsearch是Java开发的,所以首先要安装Java环境
下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
下载好之后,直接安装, 切记:不要安装在C盘!, 注意环境变量的配置(JAVA_HOME)

2. 安装elasticsearch-rtf

  不建议安装elasticsearch的官网版本,因为集成的插件比较少
下载地址:https://github.com/medcl/elasticsearch-rtf
该版本集成了一些会用到的插件。

解压后,在bin目录下打开命令行工具,输入elasticsearch.bat执行脚本,打开浏览器,在地址栏输入http://127.0.0.1:9200, 如果返回数据则表示运行成功

3.安装elasticsearch-head

  这是(搜索引擎)的可视化管理工具,安装要用到node.js的npm 插件管理器,所以要先安装node.js的npm 插件管理器。

下载地址:https://nodejs.org/en/download/
下载完成后,根据指引安装即可

(1)安装完后后,打开命令行工具

    执行命令 npm

  npm命令是node.js的npm插件管理器,也就是下载插件和安装插件的管理器,国外镜像很慢可能会掉线,我们使用淘宝的npm镜像cnpm

    执行命令:npm install -g cnpm --registry=https://registry.npm.taobao.org  

启用淘宝的npm镜像cnpm,注意:启用后当我们要输入npm命令时,就需要输入cnpm

(2)(搜索引擎)的可视化管理工具elasticsearch-head的安装

    下载地址:https://github.com/mobz/elasticsearch-head

    下载后解压到指定目录

(3)cd进入到解压的elasticsearch-head目录,安装elasticsearch-head的依赖包

    执行命令:cnpm install

    
(4)启动elasticsearch-head(搜索引擎)的可视化管理工具,访问http://localhost:9100/,就可以看到(搜索引擎)的可视化管理工具。

    执行命令:cnpm run start  

点击连接会发现是灰色的未连接状态,这是因为elsaticsearch的安全策略,在5.0之后的版本不允许第三方插件直接连接,需要修改配置文件,在config文件夹下后缀为yml的文件中添加以下配置:

    http.cors.enabled: true
    http.cors.allow-origin: "*"

重启服务,点击连接,即可成功

应用

  elasticsearch的详细内容还请参阅相关文档,接下来会直接贴上我在使用elasticsearch来实现搜索引擎时的步骤和一些注意事项。搜索引擎是为了数据而存在的,所以你需要准备一个数据源,因此我用scrapy实现了一个简单的爬虫。
  在使用前,为了准备数据要先启动爬虫将数据提交到elasticsearch,如感兴趣具体可前往https://github.com/xinyan818/SimpleSearch-TST

1.声明doc_type

  doc_type在elasticsearch中类似关系型数据库中的数据表,我们需要实现它。

# 数据类型
from elasticsearch_dsl import DocType, Completion, Keyword, Text, Boolean, Integer, Date
# 引入链接函数
from elasticsearch_dsl.connections import connections
# 引入elasticsearch中的分析器
from elasticsearch_dsl.analysis import CustomAnalyzer

# 创建Es链接
connections.create_connection(hosts=["127.0.0.1"])


# 自定义分词器
class MyAnalyzer(CustomAnalyzer):

    def get_analysis_definition(self):
        return {}

# 创建分析器对象
# 忽略大小写的筛选器


ik_analyzer = MyAnalyzer('ik_max_word', filter=['lowercase'])


class NewsType(DocType):

    # 搜索建议字段
    # Completion 用来做搜索建议的类型
    # 不能直接指定分词器名,需要指定一个自定义分词器
    suggest = Completion(analyzer=ik_analyzer)

    # 分词
    title = Text(analyzer="ik_max_word")
    category = Text()
    f_url = Text()
    intro = Text(analyzer="ik_max_word")
    source = Text()
    time = Date()

    # Meta
    class Meta:
        # 索引名称
        index = 'news'
        doc_type = 'fashion'


if __name__ == '__main__':
    NewsType.init()

  运行这个python文件即可在服务中声明一个名为news的index,和在其之下名为fashion的type,

2.搜索结果的视图函数

#搜索结果页面
def result(request):
    if request.method == 'GET':
        # 取出关键词 搜索类型 页码
        keyword = request.GET.get('kw', None)
        s_type = request.GET.get('s_type', 'blog')
        page_num = request.GET.get('pn', 1)
        # 没有关键词,定向到首页
        if not keyword:
            return redirect('/')
        # 判断搜索类型
        # 搜索
        if s_type == 'news':
            # 1. 搜索的索引
            index = 'news'
            doc_type = 'fashion'
            fields = ['title', 'intro']
            start = datetime.now()
            rs = es.search(
                index=index,
                doc_type=doc_type,
                body={
                    'query': {
                        'multi_match': {
                            'query': keyword,
                            'fields': fields
                        }
                    },
                    'from': (int(page_num)-1)*10,
                    'size': 10,
                    'highlight': {
                        'pre_tags': ['<span class="KeyWord">'],
                        'post_tags': ['</span>'],
                        'fields': {
                            'title': {},
                            'intro': {}
                        }
                    }
                }
            )
            # 搜索花费时间
            # total_seconds() 统计秒数
            use_time = (datetime.now() - start).total_seconds()
            hits_list = []
            for hit in rs['hits']['hits']:
                try:
                    h_dic = {}
                    # 判断highlight中有没有title
                    if 'title' in hit['highlight'].keys():
                        h_dic['title'] = hit['highlight']['title'][0]
                    else:
                        h_dic['title'] = hit['_source']['title']

                    # 再判断intro
                    if 'intro' in hit['highlight'].keys():
                        intro_list = hit['highlight']['intro']
                        intro_list.reverse()
                        h_dic['content'] = ''.join(intro_list)
                    else:
                        h_dic['content'] = hit['_source']['intro']

                    # 详情地址
                    h_dic['detail_url'] = hit['_source']['f_url']
                except:
                    continue
                hits_list.append(h_dic)
            navs = NAVS
            # 计算页码
            total = rs['hits']['total']

            page_nums = int(math.ceil(total/10))

            page_num = int(page_num)
            if page_num < 6:
                if page_nums <= 10:
                    pages = range(1, page_nums+1)
                else:
                    pages = range(1, 11)
            elif (page_num >= 6) and (page_num <= page_nums - 5):


                pages = range(page_num - 5, page_num + 5)
            else:
                if page_nums <= 10:
                    pages = range(1, page_nums+1)
                else:
                    pages = range(page_nums-9, page_nums + 1)

            data = {
                'navs': navs,
                'search_type': s_type,
                'hits_list': hits_list,
                'kw': keyword,
                'pages': pages,
                'page_nums': page_nums,
                'pn': page_num,
                'total': total,
                'use_time': use_time
            }
            return render(request, 'result.html', data)

猜你喜欢

转载自blog.csdn.net/xinyan233/article/details/80517562