Elasticsearch - 上一个/下一个功能

时间:2015-01-20 16:02:35

标签: php elasticsearch pagination

我创建了一个搜索引擎来搜索我的elasticsearch索引中的所有文档。当用户点击搜索结果页面上的文档时,他将离开当前页面并打开该文档的deatailpage。

现在我想在该详细信息页面上实现一个小文档导航,但我无法弄清楚如何使用elasticsearch创建这样的东西。我希望在该文档详细信息页面的顶部有一个上一个文档和一个下一个文档链接。

我的想法是将所有返回的文档保存在会话cookie或其他内容中,以便记住当前搜索中的下一个和上一个文档。但我也对该搜索结果页面进行了分页。当用户选择结果页面上的最后一个文档时,下一个链接将无法工作,因为我当前的搜索没有更多文档。

这是一个常见问题还是具体问题?你们中的任何人都有一个想法可以帮助我解决这个问题吗? 也许是scroll-API

由于

2 个答案:

答案 0 :(得分:1)

以下作品对我来说非常有效。确保您使用的是sort定义的常规格式列表,如下所示:

function getSortDefinitions() {
    return [
        'newest' => [
            [ 'created_at' => 'desc' ],
            [ 'id' => 'desc' ],
        ],
        'oldest' => [
            [ 'created_at' => 'asc' ],
            [ 'id' => 'asc' ],
        ]
        'highest' => [
            [ 'price' => 'desc' ],
            [ 'created_at' => 'desc' ],
            [ 'id' => 'desc' ],
        ],
        'lowest' => [
            [ 'price' => 'asc' ],
            [ 'created_at' => 'asc' ],
            [ 'id' => 'asc' ],
        ],
    ];
}

抛开:添加id使得结果集对具有相同时间戳的记录具有可预测的排序。这通常发生在测试装置中,其中记录全部同时保存。

现在每当有人搜索时,他们通常会选择一些过滤器,可能是查询,绝对是排序顺序。创建一个存储此表的表,以便您可以生成要使用的搜索上下文:

create table search_contexts (
    id int primary,
    hash varchar(255) not null,
    query varchar(255) not null,
    filters json not null,
    sort varchar(255) not null,

    unique search_contexts_hash_uk (hash)
);

使用您选择的语言中的以下内容插入并获取对搜索上下文的引用:

function saveSearchContext($query, $filters, $sort)
{
    // Assuming some magic re: JSON encoding of $filters
    $hash = md5(json_encode(compact('query', 'filters', 'sort')));
    return SearchContext::firstOrCreate(compact('hash', 'query', 'filters', 'sort'));
}

请注意,如果没有相同参数的搜索上下文,我们只会插入搜索上下文。因此,每次搜索最终会得到一个唯一的行。您可以选择被卷淹没,并为每次搜索保存一个。如果您选择这样做,请使用uniqid代替md5,然后创建记录。

在结果索引页面上,每当您生成指向详细信息页面的链接时,请使用散列作为查询参数,如下所示:

http://example.com/details/2456?search=7ddf32e17a6ac5ce04a8ecbf782ca509

在您的详细页面代码中,执行以下操作:

function getAdjacentDocument($search, $documentId, $next = true) {
    $sortDefinitions = getSortDefinitions();

    if (!$next) {
        // Reverse the sort definitions by looping through $sortDefinitions
        // and swapping asc and desc around
        $sortDefinitions = array_map($sortDefinitions, function ($defn) {
            return array_map($defn, function ($array) {
                $field = head(array_keys($array));
                $direction = $array[$field];

                $direction = $direction == 'asc' ? 'desc' : 'asc';

                return [ $field => $direction ];
            });
        });
    }

    // Add a must_not filter which will ensure that the
    // current page's document ID is *not* in the results.
    $filters['blacklist'] = $documentId;

    $params = [
        'body' => [
            'query' => generateQuery($search->query, $filters),
            'sort' => $sortDefinitions[$sort],

            // We are only interested in 1 document adjacent
            // to this one, limit results
            'size' => 1
        ]
    ];

    $response = Elasticsearch::search($params);

    if ($response['found']) {
        return $response['hits']['hits'][0];
    }
}

function getNextDocument($search, $documentId) {
    return getAdjacentDocument($search, $documentId, true);
}

function getPreviousDocument($search, $documentId) {
    return getAdjacentDocument($search, $documentId, false);
}

// Retrieve the search context given it's hash as query parameter
$searchContext = SearchContext::whereHash(Input::query('search'))->first();

// From the route segment
$documentId = Input::route('id');

$currentDocument = Elasticsearch::get([
    'id' => $documentId,
    'index' => 'documents'
]);

$previousDocument = getPreviousDocument($searchContext, $documentId);
$nextDocument = getNextDocument($searchContext, $documentId);

这项技术的关键是除了生成两个搜索之外 详细记录的get

从该记录开始进行一次搜索,另一次从该记录向后搜索, 在两种情况下给出相同的搜索上下文,以便它们彼此协调工作。

在这两种情况下,您都会获取我们当前记录的第一条记录 是对的。

答案 1 :(得分:-1)

如果您的文档正在使用顺序_id,那么您只需执行当前文档_id + 1并再次查询。