Elasticsearch和PHP

    科技2022-08-05  104

    Elasticsearch是您可能要在下一个项目中使用的最先进的全文搜索引擎。它基于类似NoSQL的文档存储,并针对惊人的快速搜索查询进行了优化。强大的API启用了以下功能:模糊匹配(在搜索“ Torronto”时查找“ Toronto”),词干(在“ racing”中查找“ race”)和n-gram(在“ ghett”中查找“ spaghetti”)。

    在本文中,我将向您展示如何使用PHP设置Elasticsearch实例以及如何轻松执行查询。

    因此您可以通过将请求发送到来与容器的REST API通信localhost:9200,例如:

    curl -XGET http://127.0.0.1:9200/_cat/health

    如果到目前为止一切正常,此命令应返回以下输出:

    1536999057 08:10:57 docker-cluster green 1 1 0 0 0 0 0 0 - 100.0%

    新增文档

    在我们设置一个简单的PHP应用程序以与Elasticsearch通信之前,我将向您展示如何直接通过HTTP使用REST API添加文档。

    curl -H "Content-Type: application/json" -XPOST "http://127.0.0.1:9200/firstindex/user" -d "{ \"firstname\" : \"Donald\", \"lastname\" : \"Trump\"}"

    我们使用该curl命令将POST请求发送到Elasticsearch服务器。/firstindex指定我们要将文档添加到该特定索引(您可以将其视为数据库)–如果尚不存在,则会自动创建该文档。此外,我们将文档添加到类型中user(对应于关系数据库中的表)。该文档本身以JSON格式传递,由两个字段(firstname和lastname)及其各自的值组成。

    为了演示搜索功能,让我们再添加两个用户:

    curl -H "Content-Type: application/json" -XPOST "http://127.0.0.1:9200/firstindex/user" -d "{ \"firstname\" : \"Barack\", \"lastname\" : \"Obama\"}"

    curl -H "Content-Type: application/json" -XPOST "http://127.0.0.1:9200/firstindex/user" -d "{ \"firstname\" : \"Melania\", \"lastname\" : \"Trump\"}"

    搜寻文档

    在创建更复杂的查询之前,让我们首先验证输入的数据是否已保存:

    curl -XGET "http://127.0.0.1:9200/firstindex/user/_search/?pretty=true"

    这将在索引firstindex中查询类型为user的所有文档。输出(根据参数?pretty = true的请求)应正确设置格式,并等效于以下内容:

    {

      "took" : 2,

      "timed_out" : false,

      "_shards" : {

        "total" : 5,

        "successful" : 5,

        "skipped" : 0,

        "failed" : 0

      },

      "hits" : {

        "total" : 3,

        "max_score" : 1.0,

        "hits" : [

          {

            "_index" : "firstindex",

            "_type" : "user",

            "_id" : "F1ZQ3GUBPff1ZX4kkcru",

            "_score" : 1.0,

            "_source" : {

              "firstname" : "Barack",

              "lastname" : "Obama"

            }

          },

          {

            "_index" : "firstindex",

            "_type" : "user",

            "_id" : "GFZQ3GUBPff1ZX4kqMrp",

            "_score" : 1.0,

            "_source" : {

              "firstname" : "Melania",

              "lastname" : "Trump"

            }

          },

          {

            "_index" : "firstindex",

            "_type" : "user",

            "_id" : "FlZM3GUBPff1ZX4kLcq5",

            "_score" : 1.0,

            "_source" : {

              "firstname" : "Donald",

              "lastname" : "Trump"

            }

          }

        ]

      }

    }

    如您所见,所有三个用户均已成功获取。Elasticsearch还输出有关查询花费了多长时间(以毫秒为单位),产生了多少结果以及对于每个检索到的文档的索引,类型和标识符的附加信息。

    现在,您可以index.php在喜欢的文本编辑器中打开文档,并将其更改为以下内容:

    <h1>Search Results</h1>

     

    <ul>

        <li>First Result</li>

        <li>Second Result</li>

    </ul>

    重新加载浏览器时,PHPInfo应该消失了,并且简单的前端模板也应该可见。

    设置Elasticsearch-PHP

    我们可以curl像在第一部分中那样与Elasticsearch服务器通信。但是,使用elasticsearchPHP软件包要方便得多。我们将使用composer安装它。

    apt-get update ; apt-get install -y wget git ; wget https://getcomposer.org/composer.phar

    php composer.phar require elasticsearch/elasticsearch

    composer完成魔术之后,elasticsearch软件包(及其所有依赖项)已下载到该vendor/文档夹中。

    现在,我们可以将index.php文档更改为以下内容(说明如下):

    <?php

     

    require 'vendor/autoload.php';

    use Elasticsearch\ClientBuilder;

    $hosts = [

        'elasticsearch:9200',         // IP + Port

    ];

    $client = ClientBuilder::create()

                        ->setHosts($hosts)

                        ->build();

     

    $params = [

        'index' => 'firstindex',

        'type' => 'user',

        'body' => [

            'query' => [

                'match' => [

                    'lastname' => 'Trump'

                ]

            ]

        ]

    ];

     

    $response = $client->search($params);

    echo '<pre>', print_r($response, true), '</pre>';

     

     

    ?>

     

    <h1>Search Results</h1>

     

    <ul>

        <li>First Result</li>

        <li>Second Result</li>

    </ul>

     

    让我们快速地逐行浏览。

    require 'vendor/autoload.php';

    我们导入Composer的自动加载器,因此不必担心分别包含每个类文档。

    use Elasticsearch\ClientBuilder;

    导入名称空间,以便我们可以使用ClientBuilder该类而无需明确提及其名称空间。

    $hosts = [

        'elasticsearch:9200',         // IP + Port

    ];

    这配置了我们的Elasticsearch服务器可访问的位置。由于我们已将两个容器配置为位于同一个Docker网络中,因此我们可以直接引用该容器的名称,然后Docker自动将其解析为其IP。

    $client = ClientBuilder::create()

                        ->setHosts($hosts)

                        ->build();

    这将实例化一个ClientBuilder用作Elasticsearch服务器接口的对象。

    $params = [

        'index' => 'firstindex',

        'type' => 'user',

        'body' => [

            'query' => [

                'match' => [

                    'lastname' => 'Trump'

                ]

            ]

        ]

    ];

    在这里,我们指定搜索参数。对于我们的示例,我们希望从indexfirstindex类型的index接收所有文档user,其中文档值lastname等于Trump(直接匹配)。

    $response = $client->search($params);

    echo '<pre>', print_r($response, true), '</pre>';

    我们执行查询(注意,实际上它不是在运行PHP应用程序的容器中执行,而是发送到另一个运行Elasticsearch的容器中)并输出结果。该<pre>标签确保我们的输出易读。

    index.php再次在浏览器中打开时,我们将看到以下输出:

    Array

    (

        [took] => 9

        [timed_out] =>

        [_shards] => Array

            (

                [total] => 5

                [successful] => 5

                [skipped] => 0

                [failed] => 0

            )

     

        [hits] => Array

            (

                [total] => 2

                [max_score] => 0.6931472

                [hits] => Array

                    (

                        [0] => Array

                            (

                                [_index] => firstindex

                                [_type] => user

                                [_id] => bo573GUB5GzvNJfl38JF

                                [_score] => 0.6931472

                                [_source] => Array

                                    (

                                        [firstname] => Donald

                                        [lastname] => Trump

                                    )

     

                            )

     

                        [1] => Array

                            (

                                [_index] => firstindex

                                [_type] => user

                                [_id] => cY583GUB5GzvNJflIMI-

                                [_score] => 0.2876821

                                [_source] => Array

                                    (

                                        [firstname] => Melania

                                        [lastname] => Trump

                                    )

     

                            )

     

                    )

     

            )

     

    )

    您可以看到该查询产生了两个结果。

    创建比赛清单

    总结本文,我们将在HTML模板中将匹配项输出为名字和姓氏列表。

    首先,index.php由于我们仅将此行用作概念验证,因此我们将其删除:

    echo '<pre>', print_r($response, true), '</pre>';

    接下来,我们将从Elasticsearch输出创建结果数组:

    $resultNames = array_map(function($item) {

        return $item['_source'];

    }, $response['hits']['hits']);

    我们array_map用来将输出数组转换成一个[firstname, lastname]元组列表。

    最后,我们修改HTML模板:

    <h1>Search Results</h1>

     

    <ul>

    <?php foreach($resultNames as $resultName): ?>

        <li><?php echo implode(' ', $resultName); ?></li>

    <?php endforeach; ?>

    </ul>

    对于每个搜索结果,我们输出名字和姓氏,以空格分隔。该<li>标签创建一个无序列表。我们的代码应生成以下结果:

    Processed: 0.014, SQL: 8