Sorting_by_multiple_fields.md

Translated by ChatGTP

按多個字段排序

如果你想同時排序多個字段,甚至更複雜的邏輯,那麼我的解決方案是編寫痛點脚本。

多重排序查詢

    private function convertSortingSource($type, $order, $fields)
    {
        switch ($type) {
            case 'multiFields-int':
                $source    = 'Long date;';
                $operation = 'date ' . (($order === 'desc') ? '<' : '>');

                break;
            case 'multiFields-date':
                $source   = 'JodaCompatibleZonedDateTime date;';
                $operation = 'date.' . (($order === 'desc') ? 'isBefore' : 'isAfter');
        }

        foreach ($fields as $field) {
            $source .= '
                    if (
                        (doc["'. $field .'"].size() != 0) &&
                        (
                            (date == null) ||
                            (' . $operation . '(doc["'. $field .'"].value))
                        )
                    ) {';
                        switch ($type) {
                            case 'multiFields':
                            case 'multiFields-int':
                                $source .= 'date = doc["'. $field .'"].value;';
                                break;
                            case 'priority':
                                $source .= 'return doc["'. $field .'"].value.toInstant().toEpochMilli() / 1000;';
                                break;
                            default:
                                return '';
                        }
          $source .= '}';
        }

        switch ($type) {
            case 'multiFields-int':
                $source .= 'return (date == null) ? 0 : date;';

                break;
            default:
                $defaultTime = ($order === 'asc') ? Carbon::now()->addYears(10)->timestamp : 0;
                $source .= 'return (date == null) ? ' . $defaultTime . ' : date.toInstant().toEpochMilli() / 1000;';
        }

        return $source;
    }

通過不同的類型計算排序分數,在痛點中運行。

主要搜索函數

    public function search(
        $searchIndex,
        $conditions,
        $startPage = 0,
        $size = 200000,
        $sortBy = 'created_at',
        $order = 'asc',
        $sortFiledNotExists = false,
        $selectFields = null,
        $sortingCondition = []
    )
    {
        if (($sortFiledNotExists === true)) {
            $sortQuery = [
                '_script' => [
                    'type' => 'number',
                    'script' => [
                        'inline' => '(0 == doc["' . $sortBy . '"].size()) ? -1 : doc["' . $sortBy . '"].value;'
                    ],
                    'order' => $order
                ]
            ];
        } else if (
            (isset($sortingCondition['type'])) &&
            ($sortingCondition['type']) &&
            (isset($sortingCondition['fields'])) &&
            (count($sortingCondition['fields']) > 0)
        ) {
            $sortQuery = [
                '_script' => [
                    'type'   => 'number',
                    'order'  => $order,
                    'script' => [
                        'lang'   => 'painless',
                        'source' => $this->convertSortingSource(
                            $sortingCondition['type'],
                            $order,
                            $sortingCondition['fields']
                        ),
                    ],
                ]
            ];
        } else {
            $sortQuery = [
                [
                    '_score' => [
                        'order' => $order,
                    ]
                ],
                [
                    $sortBy => [
                        'order' => $order,
                        'missing' => '_last'
                    ],
                ]
            ];
        }

        $params = [
            'index' => $searchIndex,
            'body'  => [
                'track_total_hits' => true,
                'query' => [
                    'bool' => $conditions
                ],
                'sort' => $sortQuery,
            ],
            'from' => $startPage,
            'size' => $size
        ];

        if ($selectFields !== null) {
            $params['_source'] = $selectFields;
        }

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

        return $response['hits'];
    }

還有三種排序類型,不存在字段排序,多字段排序和正常排序。