【问题标题】:Elasticsearch - previous/next functionalityElasticsearch - 上一个/下一个功能
【发布时间】:2015-03-18 22:44:13
【问题描述】:

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

现在我想在该详细信息页面上实现一个小文档导航,但我不知道如何使用 elasticsearch 创建类似的东西。我希望在该文档详细信息页面的顶部有上一个文档和下一个文档链接。

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

这是一个常见问题还是特定问题?你们中有人有什么想法可以帮助我解决这个问题吗? 也许是scroll-API

谢谢

【问题讨论】:

  • 您找到解决方案了吗?
  • 是的。我只是将查询保存在会话中并计算下一个和上一个元素。
  • @Stillmatic1985:上面写着:“滚动不适用于实时用户请求”。你能解释一下你的算法和解决方案吗,(很高兴分享)我不明白它是如何工作的。
  • 我没有使用滚动。我只是将整个查询保存在会话中,对于下一个或上一个文档,我使用该查询并操纵大小和参数。

标签: php elasticsearch pagination


【解决方案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 用于详细记录。

一个搜索从该记录向前,另一个从该记录向后搜索, 在这两种情况下给定相同的搜索上下文,因此它们可以相互配合。

在这两种情况下,您都会获取第一条不是我们当前记录的记录,它应该 是正确的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 如果您仅按 ID 升序排序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-24
    • 2020-11-09
    • 1970-01-01
    • 2015-10-19
    相关资源
    最近更新 更多