2015-01-20 11 views
6

Stworzyłem wyszukiwarkę, która przeszuka wszystkie dokumenty w indeksie elasticsearch. Kiedy użytkownik trafi na dokument na stronie wyników wyszukiwania, opuści bieżącą stronę i otworzy stronę z opisem tego dokumentu.Elasticsearch - poprzednia/następna funkcjonalność

Teraz idę zaimplementować małą nawigację po dokumencie na tej stronie szczegółów, ale nie mogę wymyślić, jak stworzyć coś takiego przy pomocy elasticsearch. Chciałbym mieć poprzedni dokument i następny link do dokumentu na górze tej strony szczegółów dokumentu.

Mój pomysł polegał na zapisaniu wszystkich zwróconych dokumentów w pliku cookie sesji lub czymś innym, aby zapamiętać następny i poprzedni dokument dotyczący bieżącego wyszukiwania. Ale mam również paginację na tej stronie wyników wyszukiwania. Kiedy użytkownik wybierze ostatni dokument na stronie wyników, następny link nie zadziała, ponieważ moje obecne wyszukiwanie nie zawiera więcej dokumentów.

Czy jest to typowy problem, czy konkretny? Ktoś z was ma pomysł, który może mi pomóc rozwiązać ten problem? Być może scroll-API?

Dzięki

+0

czy otrzymałeś rozwiązanie? – richardwhatever

+0

tak. po prostu zapisuję zapytanie w sesji i obliczam następny i poprzedni element. – Stillmatic1985

+0

@ Stillmatic1985: Napisano: "Przewijanie nie jest przeznaczone dla żądań użytkowników w czasie rzeczywistym". Czy możesz wyjaśnić swój algorytm i rozwiązanie (byłoby fajnie udostępniać) Nie widzę, jak to działa. – COil

Odpowiedz

-1

Jeśli dokumenty są za pomocą sekwencyjnej _id następnie można po prostu zrobić bieżącego dokumentu _id + 1 i kwerendy go ponownie.

+0

Jeśli sortujesz według ID rosnąco tylko. – datashaman

1

Poniższe działa pięknie dla mnie. Upewnij się, że używasz regularnie sformatowaną listę sort definicji tak:

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

na marginesie: Dodawanie id czyni resultset mieć przewidywalną zamawianie rekordów z tym samym znacznikiem czasu. Zdarza się to często przy testowaniu urządzeń, w których wszystkie zapisy są zapisywane w tym samym czasie.

Teraz, gdy ktoś wyszukuje, wybrał zazwyczaj kilka filtrów, być może zapytanie i zdecydowanie porządek sortowania. Utwórz tabelę, która przechowuje to tak można wygenerować kontekstu wyszukiwarki do pracy z:

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

użyć coś jak poniżej w wybranym języku, aby wstawić i uzyskać odniesienie do kontekstu frazy:

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

Należy zauważyć, że kontekst wyszukiwania jest wstawiany tylko wtedy, gdy nie ma już takiego samego o tych samych parametrach. Tak więc kończymy z jednym unikalnym wierszem na wyszukiwanie. Możesz zdecydować się na przytłoczenie głośnością i zapisać jeden na wyszukiwanie. Jeśli zdecydujesz się to zrobić, użyj uniqid zamiast md5 i po prostu utwórz rekord.

Na stronie indeksu wyniki, gdy wygenerować link do strony szczegółów, użyj skrótu jako parametr kwerendy jak poniżej:

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

W swojej szczegółów kodzie strony, zrób coś takiego:

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

Kluczem do tej techniki jest generowanie dwóch wyszukiwań oprócz dla get dla rekordu szczegółów.

Jedna wyszukiwarka idzie do przodu z tej płyty, drugi idzie do tyłu z tego rekordu, danym ten sam kontekst wyszukiwania w obu przypadkach tak pracują w zgodzie z siebie.

W obu przypadkach należy przyjąć pierwszy rekord, który jest , a nie nasz aktualny rekord, i powinien on być poprawny .