Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elasticsearch - 最受欢迎的搜索引擎 #21

Open
dolphin836 opened this issue Jun 18, 2020 · 0 comments
Open

Elasticsearch - 最受欢迎的搜索引擎 #21

dolphin836 opened this issue Jun 18, 2020 · 0 comments

Comments

@dolphin836
Copy link
Owner

dolphin836 commented Jun 18, 2020

Elasticsearch 是一个分布式数据搜索和存储引擎
本文使用的版本为 Elasticsearch 7.8

导航

Elasticsearch 官网

Elasticsearch GitHub 主页

Elastic 中文社区

Elasticsearch 英文文档

Elasticsearch PHP

Elasticsearch 中文分词插件 IK

简介

Elasticsearch 是一个基于 Apache Lucene 的开源搜索引擎,无论是开源还是专有领域,Lucene 可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库,Lucene 非常复杂,而 Elasticsearch 通过 RESTful API 隐藏了 Lucene 的复杂性,让搜索变得更简单,不过 Elasticsearch 不仅仅是一个搜索,它更是文档型 NoSQL 的一种。

特性

  • 分布式的实时文档存储,每个字段都可以被索引并可被搜索
  • 分布式的实时分析搜索引擎
  • 可以扩展到上百台大集群,处理 PB 级结构化或非结构化数据
  • 通过 RESTful API 调用,满足各种编程语言的需求

应用

元数据定义

    /**
     * 汇报的元数据字段定义
     */
    const INDEX_MAPPING_PROPERTIES_WORK_REPORT = [
           'work_report_id' => ['type' => 'long'], // 汇报 Id
                  'user_id' => ['type' => 'long'], // 汇报用户
               'to_user_id' => ['type' => 'long'], // 汇报对象
                     'date' => ['type' => 'date', 'format' => 'yyyy-MM-dd'], // 汇报日期
         'last_update_time' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss'], // 最后更新时间
           'last_sync_time' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss'], // 数据同步时间
                  'content' => [ // 汇报内容
                       'type' => 'text',
                   'analyzer' => 'ik_max_word', // 索引时的分词模式:会将文本做最细粒度的拆分
            'search_analyzer' => 'ik_smart'     // 搜索时的分词模式:会做最粗粒度的拆分
        ],
                 'username' => [ // 用户名称
                       'type' => 'text',
                   'analyzer' => 'username_analyzer',
            'search_analyzer' => 'keyword',
        ],
        'project_task_name' => [ // 项目名称
                       'type' => 'text',
                   'analyzer' => 'ik_max_word',
            'search_analyzer' => 'ik_smart'
        ],
              'work_report' => ['type' => 'keyword']
    ];

中文人名

检索人名的时候,最好的效果其实就是模糊匹配,以“诸葛亮”为例,通过“诸”、“葛”、“亮”、“诸葛”、“葛亮”、“诸葛亮”都能搜到

Elasticsearch 自带的 standard 分词器在处理中文的时候会直接分割成单字,而中文分词插件 IK 会根据中文语义进行分词,例如“张成功”,会被分成“张”和“成功”,因为“成功”在中文中是一个词语,这两种方式显然都不满足我们的要求

Elasticsearch 自带的 N-gram 分词器可以满足我们的要求,在创建 Index 的时候,设置一个自定义分词器 username_analyzer,然后将人名字段的分词器设置为 username_analyzer 就可以了

创建 Index

$data = [
    'index' => $indexName,
     'body' => [
        'settings' => [
            'index.max_ngram_diff' => 3,
                        'analysis' => [
                 'analyzer' => [
                    'username_analyzer' => [
                        'tokenizer' => 'username_tokenizer'
                    ]
                ],
                'tokenizer' => [
                    'username_tokenizer' => [
                               'type' => 'ngram',
                           'min_gram' => 1,
                           'max_gram' => 4,
                        'token_chars' => []
                    ]
                ]
            ]
        ]
    ]
];

index.max_ngram_diff 的默认值为 1,max_gram 减去 min_gram 的值不得大于 1,所以这里我们需要一起设置 index.max_ngram_diff 的值为 3,这样就可以处理 4 个字的人名

自定义词库

IK 中文分词插件允许自定义词库,分为两块:自定义字典、自定义停止字典

例如产品名称、项目名称、专用名词等,默认情况下 IK 插件肯定是不能很好的处理的,需要我们通过自定义字典提供给 IK

而有的词 IK 把它当作一个词语,而你不希望把它当作一个词语,也可以通过自定义停止字典告诉 'IK'

IK 自定义字典配置文件 [Elasticsearch 目录]/plugins/ik/config/IKAnalyzer.cfg.xml,格式

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
 	<!--用户可以在这里配置远程扩展字典 -->
	<entry key="remote_ext_dict">location</entry>
 	<!--用户可以在这里配置远程扩展停止词字典-->
	<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>

总共 4 项,不需要的可以注释掉

本地的非常简单,在同级目录下有已经有很多的字典文件,是 IK 提供的范本,可以参考新建我们自己的

在实际的应用场景中,肯定是通过接口来实现远程更新更好,远程更新接口需要注意必须包含这么几个 Header 参数 Last-ModifiedEtagConnectionKeep-AliveContent-Length

当字典更新时,要保证 Last-ModifiedEtag 两个参数至少有一个更新

        $wordText = implode(PHP_EOL, $wordArr);

        return response($wordText, 200)->header('Content-Type', 'text/plain')
                                                           ->header('Last-Modified', date('D, d M Y H:i:s e', $lastUpdateTime))
                                                           ->header('Etag', md5($wordText))
                                                           ->header('Connection', 'keep-alive')
                                                           ->header('Keep-Alive', 'timeout=4')
                                                           ->header('Content-Length', strlen($wordText));
@dolphin836 dolphin836 changed the title Elasticsearch API Elasticsearch 应用笔记 Jul 21, 2020
@dolphin836 dolphin836 self-assigned this Jul 22, 2020
@dolphin836 dolphin836 changed the title Elasticsearch 应用笔记 Elasticsearch - 最受欢迎的搜索引擎 Jul 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant