php使用elasticsearch

1.引入包
composer require elasticsearch/elasticsearch

2.DEMO参考

<?php
require_once './vendor/autoload.php';

use Elasticsearch\ClientBuilder;

$hosts = [
    [
        'host' => '192.168.56.201',
        'port' => '9200',
        'scheme' => 'http',
        //'user' => 'username',
        //'password' => 'password'
    ],
];
try {
    $client = ClientBuilder::create()->setHosts($hosts)->build();
    //创建index并设置mapping
    /*$params = [
        'index' => 'demo',  //索引名(相当于关系型mysql的数据库)
        'body' => [
            'settings' => [
                'number_of_shards' => 1,  //分片数
                'number_of_replicas' => 1, //副本分骗术
            ],
            'mappings' => [
                'm_type' => [
                    '_all' => [
                         'enabled' => 'false'
                    ],
                    '_routing' => [
                        'required' => 'true'
                    ],
                    'properties' => [ //文档类型设置(相当于mysql的数据类型)
                        'name' => [
                            'type' => 'string',
                            'store' => 'true'
                        ],
                        'age' => [
                            'type' => 'integer'
                        ]
                    ]
                ]
            ]
        ]
    ];
    $response = $client->indices()->create($params);
    print_r($response);//Array ( [acknowledged] => 1 [shards_acknowledged] => 1 )
    */
//    索引操作
//    $params = [
//        'index' => 'demo',
//    ];
//    $response = $client->indices()->delete($params);    //删除索引
//    print_r($response);//Array ( [acknowledged] => 1 )
    //$response = $client->indices()->getSettings($params);//获取索引设置信息
    //print_r($response);//Array ( [demo] => Array ( [settings] => Array ( [index] => Array ( [creation_date] => 1502246895144 [number_of_shards] => 5 [number_of_replicas] => 5 [uuid] => tW3DB-9FRQC2W-bwXl0fbg [version] => Array ( [created] => 5040199 ) [provided_name] => demo ) ) ) )
    //$response = $client->indices()->exists($params);   //检测索引是否存在
    //print_r($response);//1
    //$response = $client->indices()->getMapping($params);   //获取索引的mapping信息
    //print_r($response);//Array ( [demo] => Array ( [mappings] => Array ( [m_type] => Array ( [_all] => Array ( [enabled] => ) [_routing] => Array ( [required] => 1 ) [properties] => Array ( [age] => Array ( [type] => integer ) [name] => Array ( [type] => text [store] => 1 ) ) ) ) ) )
    
    //添加文档
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        'body' => [
//            'name' => 'demo',
//            'age' => 150
//        ],
//        'routing' => '/demo/m_type'
//    ];
//    $response = $client->index($params);
//    print_r($response);
  
    //删除文档
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        'routing' =>   '/demo/m_type'
//    ];
//    $response = $client->delete($params);
//    print_r($response);//Array ( [found] => 1 [_index] => demo [_type] => m_type [_id] => 1 [_version] => 2 [result] => deleted [_shards] => Array ( [total] => 2 [successful] => 2 [failed] => 0 ) )
    
    //修改文档
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        'body' => [
//            'doc' => [
//                'name' => 'demo22',
//                'age' => 130
//            ]
//        ],
//        'routing' =>   '/demo/m_type'
//    ];
//    $response = $client->update($params);
//    print_r($response);
    //获取文档并指定字段
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        '_source' => [
//            'age'
//        ],
//        'routing' =>   '/demo/m_type'
//    ];
//    $response = $client->get($params);
//    print_r($response);
//    $response = $client->getSource($params);
//    print_r($response);
    
    //高级搜索
//    $params = [
//        'index' => 'demo',
//        'type'  => 'm_type',
//        'routing' => '/demo/m_type',
//        'body' => [
//            'query' => [
//                'match' => [
//                    'age' => 130,
//                ]
//            ]
//        ]
//    ];
//    $response = $client->search($params);
//    print_r($response);
    
} catch (Exception $e) {
    echo $e->getMessage();
}

备注:如果提示routing_missing_exception则参数当中需要传递routing

参考:https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html

ES中的分布式搜索

一.查询阶段
查询会广播到索引的每个分片(主分片或者副本分片),每个分片搜索并构建一个匹配结果的优先队列(存储top-n文档有序列表)
步骤:
1.发送请求到协调节点,协调节点创建一个from+size的空优先队列
2.协调节点广播到索引每个分片中,每个分片查询并存储from+size的优先队列
3.每个分片返回优先队列当中的ID和排序值给协调节点,协调节点合并到自己的优先队列产生结果列表
Continue reading

ES中的查询

一、查询语句形式
1.叶子语句
2.复合语句(一条复合语句可以是多条叶子语句和多个复合语句组成)

二、查询和过滤的区别
1.过滤是将查询设置为是否匹配(只有是和否两种情况),查询会缓存
2.查询是判断文档是否匹配同时判断文档的匹配程度(_score字段),查询不缓存
Continue reading

ES的映射和分析

精确值和全文
1.ES的数据可以分为精确值和全文
2.精确值比如date类型或者long类型,全文指string类型(匹配)

分析过程:
1.文本分成适合倒排索引的独立的词条
2.将词条标准格式化为可搜索
2.1 字符过滤:去掉html或者&转换为and
2.2 分词器:其次字符串被分词器分成单个词条
2.3 过滤器:词条按照顺序通过token过滤器(小写化、删除无用词、增加同义词)
Continue reading

Elasticsearch的索引、分片、文档、副本

我们往 Elasticsearch 添加数据时需要用到 索引 —— 保存相关数据的地方。 索引实际上是指向一个或者多个物理 分片 的 逻辑命名空间 。

一个 分片 是一个底层的 工作单元 ,它仅保存了 全部数据中的一部分。 在分片内部机制中,我们将详细介绍分片是如何工作的,而现在我们只需知道一个分片是一个 Lucene 的实例,以及它本身就是一个完整的搜索引擎。 我们的文档被存储和索引到分片内,但是应用程序是直接与索引而不是与分片进行交互。

Elasticsearch 是利用分片将数据分发到集群内各处的。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。 当你的集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。

一个分片可以是 主 分片或者 副本 分片。 索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。

一个副本分片只是一个主分片的拷贝。 副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务。

在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改。

被混淆的概念是,一个 Lucene 索引 我们在 Elasticsearch 称作 分片 。 一个 Elasticsearch 索引是分片的集合。 当 Elasticsearch 在索引中搜索的时候, 他发送查询到每一个属于索引的分片(Lucene 索引),然后像 执行分布式检索 提到的那样,合并每个分片的结果到一个全局的结果集。

Elasticsearch学习搜索的笔记

1.普通查询(全文搜索)
查询name=Smith的文档数据
GET /megacorp/employee/_search
{
    "query" : {
        "match" : {
            "name" : "smith"
        }
    }
}
备注:
返回结果当中存在max_score和每个记录当中的_score表示最大相关性分数和该记录的相关性分数

2.组合查询
查询name=smith并且年龄大于30岁
GET /megacorp/employee/_search?pretty
{
    "query" : {
        "bool": {
            "must": {
                "match" : {
                    "name" : "smith" 
                }
            },
            "filter": {
                "range" : {
                    "age" : { "gt" : 30 } 
                }
            }
        }
    }
}

3.短语搜索
查询about字段当中包含rock和climbing并且rock climbing相连
GET /megacorp/employee/_search?pretty
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    }
}

4.高亮搜索
GET /megacorp/employee/_search?pretty
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    },
    "highlight": {
        "fields" : {
            "about" : {}
        }
    }
}

5.聚合查询-分析
按照interests字段进行聚合
GET /megacorp/employee/_search?pretty
{
  "aggs": {
    "all_interests": {
      "terms": { "field": "interests" }
    }
  }
}
报错:illegal_argument_exception
原因:Fielddata is disabled on text fields by default
解决办法:
PUT /megacorp/_mapping/employee
{
   "employee": {
      "properties": {
        "interests": {
          "type": "text",
          "fielddata": true
        }
      }
   }
}
备注:
interests是要聚合的字段名
查询结果当中all_interests是分析结果

6.分级汇总-分析
按照interests字段进行聚合,然后计算age平均年龄
GET /megacorp/employee/_search
{
    "aggs" : {
        "all_interests" : {
            "terms" : { "field" : "interests" },
            "aggs" : {
                "avg_age" : {
                    "avg" : { "field" : "age" }
                }
            }
        }
    }
}
备注:
avg_age是聚合结果当中新增字段

Elasticsearch的CRUD操作

1、添加信息	

PUT http://192.168.56.201:9200/demo/employee/1?op_type=create
{
	"first_name" : "John",
	"last_name" :  "Smith",
	"age" :        25,
	"about" :      "I love to go rock climbing",
	"interests": [ "sports", "music" ]
}
PUT http://192.168.56.201:9200/demo/employee/1/_create
{
	"first_name" : "John",
	"last_name" :  "Smith",
	"age" :        25,
	"about" :      "I love to go rock climbing",
	"interests": [ "sports", "music" ]
}

2、删除信息

DELETE  http://192.168.56.201:9200/megacorp/employee/1

3、搜索信息

3.1、搜索所有
GET http://192.168.56.201:9200/megacorp/employee/_search
3.2、搜索指定ID
GET http://192.168.56.201:9200/megacorp/employee/1
3.3、按照关键词搜索
GET http://192.168.56.201:9200/megacorp/employee/_search?q=last_name:Smit
其中last_name是要搜索的字段,Smith是该字段的值
3.4 使用Query  DSL查询
GET http://192.168.56.201:9200/megacorp/employee/_search
{
    "query" : {
        "match" : {
            "last_name" : "Smith"
        }
    }
}

4、更新或添加信息

PUT http://192.168.56.201:9200/demo/employee/1
{
	"first_name" : "John",
	"last_name" :  "Smith",
	"age" :        25,
	"about" :      "I love to go rock climbing",
	"interests": [ "sports", "music" ]
}
如果不存在则新建

5、乐观并发控制
在更新或者删除时可以使用_version参数来控制

6、更新部分文档部分内容
POST http://192.168.56.201:9200/demo/employee/1/_update
{
	"first_name" : "John",
	"tags":["test"]
}

7、冲突重试
POST http://192.168.56.201:9200/demo/employee/1/_update?retry_on_conflict=5
使用场景:更新文章点击次数

8、检索多个文档
GET /_mget
{
   "docs" : [
      {
         "_index" : "website",
         "_type" :  "blog",
         "_id" :    2
      },
      {
         "_index" : "website",
         "_type" :  "pageviews",
         "_id" :    1,
         "_source": "views"
      }
   ]
}
相同index和type
GET /website/blog/_mget
{
   "ids" : [ "2", "1" ]
}

9、批量操作
POST _bulk?pretty
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} 
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "My first blog post" }
{ "index":  { "_index": "website", "_type": "blog" }}
{ "title":    "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} }

备注:每行使用换行符分开,bulk操作不是原子性的;批量要注意每次提交的文档大小

logstash配置output到Elasticsearch

input {
	file {
		path => ["/data/logs/nginx/201/*.log"]
		type => "test-log"
		start_position => "beginning"
        codec => "json"
	}
}
output {
	elasticsearch {
        hosts => "192.168.56.201:9200"
        index => "nginx-201"
	}
}

更多参考:https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html