Elasticsearch简单入门及应用

时间:2021-04-10 19:58:50

来源:

多年前,一个叫做Shay Banon的刚结婚不久的失业开发者,由于妻子要去伦敦学习厨师,他便跟着也去了。在他找工作的过程中,为了给妻子构建一个食谱的搜索引擎,他开始构建一个早期版本的Lucene。

    直接基于Lucene工作会比较困难,所以Shay开始抽象Lucene代码以便Java程序员可以在应用中添加搜索功能。他发布了他的第一个开源项目,叫做“Compass”。
    后来Shay找到一份工作,这份工作处在高性能和内存数据网格的分布式环境中,因此高性能的、实时的、分布式的搜索引擎也是理所当然需要的。然后他决定重写Compass库使其成为一个独立的服务叫做Elasticsearch。

第一个公开版本出现在2010年2月,在那之后Elasticsearch已经成为Github上最受欢迎的项目之一,代码贡献者超过300人。一家主营Elasticsearch的公司就此成立,他们一边提供商业支持一边开发新功能,不过Elasticsearch将永远开源且对所有人可用。

特点:

elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。

Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

几乎每个系统都会有一个搜索的功能,当搜索做到一定程度时,维护和扩展起来难度就会慢慢变大,所以很多公司都会把搜索单独独立出一个模块,用ElasticSearch等来实现。

Elasticsearch还可用来做日志分析系统:ELK。是ElasticSearch + Logstash +Kibana 的简称。L:是一个完全开源的工具,他可以对你的日志进行收集、分析,并将其存储供以后使用(如,搜索)。 kibana 也是一个开源和免费的工具,他 Kibana 可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助您汇总、分析和搜索重要数据日志。


ElasticSearch的使用非常广泛。例如:UBER、LinkedIn、ebay等公司。

安装:

1、下载地址

https://www.elastic.co/downloads

2、两种运行方式:

   第一种:直接解压,找到bin目录,然后运行程序,用nohup或者elasticsearch –d,

https://www.elastic.co/guide/en/elasticsearch/reference/current/setup.html
     第二种:以系统服务的形式运行(推荐这种)
 官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-service.html
gitHub:
https://github.com/elastic/elasticsearch-servicewrapper

3、elasticsearch-head

辅助管理集群的可视化工具,可以用来查询数据和查看管理集群。
gitHub:
https://github.com/mobz/elasticsearch-head

4、插件

Elasticsearch本身不支持中文,需要下插件以支持中文分词
https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-smartcn.html

如果还嫌麻烦,可以直接去gitHub上看一看“elasticsearch-rft”这个项目,直接集成了elasticSearch所需的所有中文东西。https://github.com/medcl/elasticsearch-rtf

5、http client

这里选用的是官方提供的elasticsearch-php
https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html

elasticsearch创建:

1、ElasticSearch中数据名称和数据库中的对应关系

  index  ~~ database
type  ~~ table
document ~~ row

2、创建index的结构

 不创建也可以,elasticsearch本身有一些默认的配置,但是一般都是自己创建。
PUT /my_index
{
    "settings": { ... any settings ... },
    "mappings": {
        "type_one": { ... any mappings ... },
        "type_two": { ... any mappings ... },
        ...
    }

创建好的结构PHP版:

....

由于代码很长,我就不贴了

大体结构是
body:{
settings:{   
   number_of_shards:
     number_of_replicas:
   analysis { filter:{}, tokenizer:{}, analyzer:{} }
},
mappings:{
    “your_type1”:{ … properties:{  id:{ type:long … } … }
     …
}
}

3、索引设置

(Elasticsearch 提供了优化好的默认配置。除非你明白这些配置的行为和为什么要这么做,请不要修改这些配置。)
number_of_shards : elasticsearch 主分片点的个数 (默认是5)
number_of_replicas:每个分片的副本 (默认是1)

分片:

当有大量的文档时,由于内存、硬盘等硬件资源的能力,没法及时的相应客户端的请求,一个节点就不够用。这时候,数据可以分为较小的称之为分片(shard)的部分。每个分片可以放在不同的服务器上,因此,数据可以在集群节点中传播,当你查询的索引分布在多个分片上时,Elasticsearch会把查询发送给每个相关的分片,并将结果合并在一起,应用程序对于分片来讲是透明的(不知道也无需知道分片的存在)。

副本:

为了提高查询的吞吐量,可以使用副本。副本只是一个分片的精确复制,每个分片可以有零到多个副本。换句话说:Elasticsearch可以有许多相同的分片,其中之一被自动选择去更改索引操作。这种特殊的分片称之为:主分片(primary shard),其余的称之为副本分片(replica shard)。在主分片丢失的时候,例如该分片数据所在的服务器不可用,集群将副本提升为新的主分片。


 analysis 机制用于进行全文本(Full Text)的分词,以建立提供搜索用的反向索引。

   analysis 机制包含了一下步骤:
   首先,把一整块的文本分割成单独独立的用于倒排索引的词(terms)。
   然后,把这些分词整合成用于改善查询或其他操作的标准的结构。
  以上工作被analyzers完美的解决了。一个analyzers是一个整合了以下三个东西的wrapper:

Character filters(字符过滤器):

首先字符串经过字符过滤器(character filter),它们的工作是在标记化前处理字符串。字符过滤器能够去除HTML标记,或者转换"&"为"and"。

Tokenizer(分词器):

下一步,分词器(tokenizer)被标记化成独立的词。一个简单的分词器(tokenizer)可以根据空格或逗号将单词分开(这个在中文中不适用)。


filters(过滤器):

最后,每个词都通过所有标记过滤(token filters),它可以修改词(例如将"Quick"转为小写),去掉词(例如停用词像"a"、"and"``"the"等等),或者增加词(例如同义词像"jump"和"leap")

注意:整个流程就是 character filters => Tokenzier => Tokenzier filters

elastic提供了很多开箱即用的字符过滤器、分词器和过滤器,可以参照官网。
https://www.elastic.co/guide/en/elasticsearch/guide/current/analysis-intro.html
中文版:
http://es.xiaoleilu.com/052_Mapping_Analysis/40_Analysis.html
这种DSL的东西没有必要记,现用现查就行了

以下是ElasticSearch内置的Analyzer、tokenizer、tokenizer filter、character filter

Analyzer(分析器):

Analyzer
Analyzer名字 作用
standard standard tokenizer, standard filter, lower case filter, stop filter
simple lower case tokenizer
stop lower case tokenizer, stop filter
keyword 不分词,内容整体作为一个token(not_analyzed)
whitespace 正则表达式分词,默认匹配\W+
lang 各种语言
snowball standard tokenizer, standard filter, lower case filter, stop filter,snowball filter
custom 一个Tokenizer, 零个或多个Token Filter, 零个或多个Char Filter


tokenizer

standard  
edgeNGram  
keyword 不分词
letter 按单词分
lowercase letter tokenizer, lower case filter
nGram  
whitespace 以空格为分隔符拆分
pattern 定义分隔符的正则表达式
uax_url_email 不拆分url和email
path_hierarchy
处理类似/path/to/somthing样式的字符串
   

token filter  

tokenizer filter
tokenizer filter名字 tokenizer filter的作用
standard  
asciifolding  
length 去掉太长或者太短的
lowercase
转成小写
 nGram  
edgeNGram  
porterStem 波特词干算法
shingle
定义分隔符的正则表达式
stop 移除 stop words
word_delimiter 将一个单词再拆成子分词
stemmer  
stemmer_override  
keyword_marker  
keyword_repeat  
kstem  
snowball  
phonetic 插件 https://github.com/elasticsearch/elasticsearch-analysis-phonetic
synonyms
处理同义词
dictionary_decompounder,hyphenation_decompounder 分解复合词
reverse 反转字符串
elision 去掉缩略语
truncate 截断字符串
unique  
pattern_capture  
pattern_replace 用正则表达式替换
trim
去掉空格
limit 限制token数量
hunspell 拼写检查
common_grams  
arabic_normalization,persian_normalization  


character filter
character filter 的名字 character filter的作用
mapping 根据配置的映射关系替换字符
html_strip 去掉HTML元素
pattern_replace 用正则表达式处理字符串
   

ElasticSearch的基本用法:

elasticsearch的curd操作很简单:

创建 index:curl-XPUT'localhost:9200/customer?pretty'
创建 document:curl-XPUT'localhost:9200/customer/external/1?pretty'-d'{ "name": "John Doe"}'

删除 index :  curl - XDELETE 'localhost:9200/customer?pretty'
删除document:  curl - XDELETE 'localhost:9200/customer/external/2?pretty'
note:删除了index,index下面的所有document都会删除。

修改:  curl - XPOST 'localhost:9200/customer/external/1/_update?pretty' - d '{ "doc": { "name": "Jane Doe" }}'

查找:elasticSearch的查找可以非常复杂,也可以简单。
简单的: curl - XGET 'http://localhost:9200/twitter/tweet/1'
这样可以直接得到我们需要的那个document的信息
但是我们检索肯定不能这么简单,elasticsearch提供了一套查询的DSL,专门用于Query,可以去官网仔细看一下,这里就不过多赘述了
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html
   elasticsearch基本的API格式 curl  -X请求方法(大写) IP地址 :port/ES中定义的Index/ES中定义的type/document的ID。注意:elasticsearch的增加是用的PUT方法,更新是POST方法,这和一般的REST规范有所不同。
 
elasticsearch还支持批量处理
例如:先更新一个数据,然后删除另一个数据,就可以这样写:
curl - XPOST 'localhost:9200/customer/external/_bulk?pretty' - d '
{ "update":{"_id":"1"}}
{"doc": { "name": "John Doe becomes Jane Doe" } }
{"delete":{"_id":"2"}}
'

elasticsearch的集群搭建:

创建三个节点的集群:
 ElasticSearch创建集群非常的简单,把三个服务器中的elasticsearch.yml文件中的”cluster.name”改为相同的名字就可以。
Elasticsearch简单入门及应用
然后把三个节点启动就可以,无需考虑任何问题,非常的方便。

ElasticSearch在项目中的应用

1、创建index

  创建index需要考虑的东西很多:需要几个type?需要document的结构是怎样的?字段需要几种分词?等等。Index重要的分析机制是自定义的,以后想要检索得到更好的结果,主要是优化这一部分。

2、在程序中使用elasticsearch-PHP,来向ES发送rest请求。

添加一个document:
Elasticsearch简单入门及应用
添加一个index:
Elasticsearch简单入门及应用

删除一个document:
Elasticsearch简单入门及应用
Elasticsearch简单入门及应用
删除一个index:
Elasticsearch简单入门及应用Elasticsearch简单入门及应用

得到一个document:
Elasticsearch简单入门及应用
Elasticsearch简单入门及应用
修改一个document:(官网贴图没找到)

Elasticsearch简单入门及应用Elasticsearch简单入门及应用
(PS:其中data是一个php数组)

查询比较多样和复杂在此,我贴一个项目中用到的,功能:多种type联合搜索后,根据“城市”过滤结果,然后高亮显示match上的字段。
$param = [
    'index' => ESConsts::INDEX,
    'type' => [ESConsts::TYPE_DOC, ESConsts::TYPE_HOSPITAL],
    'body' => [
        'size' =>9000,
        'from' =>0,
        'query' => [
            'filtered' => [
                'query' => [
                    "multi_match" => [
                        "query" => $keyword,
                        "type" => "best_fields",
                        "fields" => [
                            "name", "hospitals_name",
                            "hospitals_name.hospitals_name_pinyin", "name.name_pinyin"
                        ],
                        "tie_breaker" => 0.3,
                        "minimum_should_match" => "10%"
                    ],
                ],
                'filter' => [
                    'term' => ['city' => $city]
                ],
            ]
        ],
        'highlight' =>[
            'fields' => [
                'hospitals_name' => [
                    "pre_tags" => ["<font color='#00FFFF'>"],
                    "post_tags" => ["</font>"]
                ],
                'name' => [
                    "pre_tags" => ["<font color='#00FFFF'>"],
                    "post_tags" => ["</font>"]
                ],
                'hospitals_name.hospitals_name_pinyin' => [
                    "pre_tags" => ["<font >"],
                    "post_tags" => ["</font>"]
                ],
                'name.name_pinyin' => [
                    "pre_tags" => ["<font >"],
                    "post_tags" => ["</font>"]
                ]
            ]
        ]
    ]
];
$response = $client->search($param);

3、ES和DB数据的一致性

   ES中的数据必须要保持和DB数据的一致,才可以得到真实的结果,否则,用户通过ES得到的数据永远都是不可用的。在项目中是通过重写model层的写库方法实现的,每当对DB进行写操作的时候,触发事件,异步向ES中发消息,然后更改ES中数据。
(通过 PHP 框架 Laravel 的Event模块实现)