Sorting_by_multiple_fields.md


Sorting by multiple fields

If you want to sorting more than one fields at the same time, or even more complex logic, then my solution is writing painless script.

Multiple sorting query

    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;
    }

Calculate sorting score by different type, and run in painless.

Main Search Function

    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'];
    }

There’s also three types of sorting, filed not exist sorting, multi-field-sorting and normal sorting