来源:

多年前,一个叫做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名字作用
standardstandard tokenizer, standard filter, lower case filter, stop filter
simplelower case tokenizer
stoplower case tokenizer, stop filter
keyword不分词,内容整体作为一个token(not_analyzed)
whitespace正则表达式分词,默认匹配\W+
lang各种语言
snowballstandard tokenizer, standard filter, lower case filter, stop filter,snowball filter
custom一个Tokenizer, 零个或多个Token Filter, 零个或多个Char Filter

 

 

tokenizer

 

 

 

standard 
edgeNGram 
keyword不分词
letter按单词分
lowercaseletter 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在项目中的应用

1、创建index

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

 

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

添加一个document:

添加一个index:

 

删除一个document:

 

删除一个index:

 

得到一个document:

 

修改一个document:(官网贴图没找到)

 

(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模块实现)

 

更多精彩内容,请关注我的微信公众账号 互联网技术窝 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐