PHP使用Elasticsearch搜索引擎

PHP使用Elasticsearch搜索引擎

注意

PHP使用Elasticsearch搜索引擎实现,要注意Elasticsearch、Elasticsearch-php与php的版本。这里我使用的是Elasticsearch 5.4.1、php 7、Elasticsearch-php5.0

Elasticsearch安装教程

PHP使用Elasticsearch

执行composer require elasticsearch/elasticsearch~5.0

连接Elasticsearch

public function __construct()
    {
        //host数组可配置多个节点
        $params = [
            'http://Elasticsearch服务器ip:9200'
        ];
        $this->es = ClientBuilder::create()->setHosts($params)->build();
    }

创建索引

    public function es_create(){
         $params = [
            'index' => 'test', //索引名称
            'body' => [
                'settings'=> [ //配置
                    'number_of_shards'=> 3,//主分片数
                    'number_of_replicas'=> 1 //主分片的副本数

                ],
                'mappings'=> [  //映射
                    '_default_' => [ //默认配置,每个类型缺省的配置使用默认配置
                        '_all'=>[   //  关闭所有字段的检索
                            'enabled' => 'false'
                        ],
                        '_source'=>[   //  存储原始文档
                            'enabled' => 'true'
                        ],
                        'properties'=> [ //配置数据结构与类型
                            'name'=> [ //字段1
                                'type'=>'string',//类型 string、integer、float、double、boolean、date
                                'index'=> 'analyzed',//索引是否精确值  analyzed not_analyzed
                            ],
                            'age'=> [ //字段2
                                'type'=>'integer',
                            ],
                            'sex'=> [ //字段3
                                'type'=>'string',
                                'index'=> 'not_analyzed',
                            ],
                        ]
                    ],
                    'my_type' => [
                        'properties' => [
                            'phone'=> [
                                'type'=>'string',
                            ],
                        ]
                    ],
                ],
            ]
        ];
        $res = $this->es->indices()->create($params);
        dd($res,1);
    }

查看Mappings

public function es_get(){
        $params = [
            'index' => 'test'
        ];
        $res = $this->es->indices()->getMapping($params);
        dd($res);
    }

修改Mappings

public function es_set(){
        $params = [
            'index' => 'test',
            'type' => 'my_type',
            'body' => [
                'my_type' => [
                    'properties' => [
                        'idcard' => [
                            'type' => 'integer'
                        ]
                    ]
                ]
            ]
        ];
        $res = $this->es->indices()->putMapping($params);
        dd($res);
    }

删除索引

public function es_del(){
        $params = [
            'index' => 'test'
        ];
        $res = $this->es->indices()->delete($params);
        dd($res);
    }

插入单条 Document

public function postBulkDoc(){
        for($i = 0; $i < 5; $i++) {
            $params['body'][] = [
                'index' => [
                    '_index' => 'test',
                    '_type' => 'my_type',
                ]
            ];

            $params['body'][] = [
                'age' => 17+$i,
                'name' => 'reimu'.$i,
                'sex' => '女性',
                'idcard' => 1112+$i,
                'phone' => '1245789'.$i,
            ];
        }
        $res = $this->es->bulk($params);
        dd($res);
    }

通过id获取Document

public function getDocById(){
        $params = [
            'index' => 'test',
            'type' => 'my_type',
            'id' => 'AX3nTLqXArjzNK3LMPwI'
        ];
        $res = $this->es->get($params);
        dd($res);
    }

file通过id更新Document

public function updateDocById(){
        $params = [
            'index' => 'test',
            'type' => 'my_type',
            'id' => 'AX3nTLqXArjzNK3LMPwI',
            'body' => [
                'doc' => [ //将doc中的文档与现有文档合并
                    'name' => 'marisa'
                ]
            ]
        ];
        $res = $this->es->update($params);
        dd($res);
    }

file通过id删除Document

public function deleteDocById(){
        $params = [
            'index' => 'test',
            'type' => 'my_type',
            'id' => 'AX3nTLqXArjzNK3LMPwI'
        ];
        $res = $this->es->delete($params);
        dd($res);
    }

file

注意:以上通过id的三个操作,如果未找到id,Elasticsearch-php会直接报错!

搜索Document

public function searchDoc()
    {
        $params = [
            'index' => 'test',
            'type' => 'my_type',
            'body' => [
                'query' => [
                    'constant_score' => [ //非评分模式执行
                        'filter' => [ //过滤器,不会计算相关度,速度快
                            'term' => [ //精确查找,不支持多个条件
                                'name' => 'reimu1'
                            ]
                        ]
                    ]
                ]
            ]
        ];
        $res = $this->es->search($params);
        dd($res);
    }

file

扩展

  1. ES中的搜索分两个概念,匹配和过滤
  2. 匹配通常针对的是字符串 类型的字段,而过滤针通常对的精确的类型,比如 integer,keyword,date等, 他们之间没有明确的规定,匹配可以去匹配data,integer等类型,过滤也可以去过滤text字段,通过匹配的方式去找精确类型通常不会出现什么问题,通过过滤去找text类型的数据通常会得到意外的结果。
  3. 如果没有特殊情况,匹配针对text类型,过滤针对其他类型,但是对于精确类型使用过滤的性能通常比匹配更高,所以能使用过滤的地方都过滤
  4. 要区别一下MySQL中的过滤概念,MySQL中的过滤是对查找后的数据进行过滤,而在ES中,过滤和匹配都等同于MySQL中的查找,匹配适合查找模糊数据,过滤适合查找精确数据而已

常用的过滤

精确查找

$query = [
    'query' => [
        'term' => [
            'name' => 'reimu1'
        ]
    ]
];

精确查找多个字段

$query = [
    'query' => [
        'terms' => [
            'name' => [ 'reimu1', 'reimu2']
        ]
    ]
];

范围查找

$query = [
    'query' => [
        'range' => [
            'age' => [
                'gt' => 15,
                'lt' => 25
            ]
        ]
    ]
];

exists(等同于MySQL中的 is not null),查找存在age属性的文档

$query = [
    'query' => [
        'exists' => [
            'field' => 'age'
        ]
    ]
];

missing(等同于 MySQL中的 is null)

注意:这个过滤方法在2.x版本就废弃了,请使用 must_not 嵌套 exists 来实现,bool(用来组合其他过滤条件,包含 must,must_not,should操作)

$query = [
    'query' => [
        'bool' => [
            'should' => [
                'range' => [
                    'age' => ['gt' => 20]
                ]
            ],
            'must_not' => [
                'term' => [
                    'info.sex' => '女性'
                ]
            ],
            'must' => [
                [
                    'term' => [
                        'info.idcard' => '114'
                    ]
                ],
                [
                    'term' => [
                        'info.phone' => '12457892'
                    ]
                ]
            ]
        ]
    ]
];

上面这个查询的意思是,年龄大于20,性别不能是女性,idcard是114且电话是12457892。

常用的查询:

match(匹配一个字段)

$query = [
    'query' => [
        'match' => [
            'name' => 'reimu2'
        ]
    ]
];

match_all(匹配所有文档,相当于没有条件)

等于是 $query = []

multi_match(匹配多个字段)

$query = [
    'query' => [
        'multi_match' => [
            'query' => '1',
            'fields' => ['phone','idcard']
        ]
    ]
];

匹配phone和idcard里面包含 '1' 的数据

bool(用来组合其他匹配条件,包含 must,must_not,should操作)

$query = [
    'query' => [
        'bool' => [
            'should' => [
                'match' => [
                    'name' => 'reimu2'
                ]
            ],
            'must_not' => [
                'match' => [
                    'info.sex' => '女性'
                ]
            ]
        ]
    ]
];

中文分词

Elasticsearch+ik实现中文分词 ES默认的分词是英文分词,对中文分词支持的并不好。所以需要安装ik中文分词。

猜你喜欢