Implementazione dei totali di impaginazione e ricerca con la ricerca FHIR

L'implementazione della ricerca FHIR dell'API Cloud Healthcare è altamente scalabile ed efficiente, pur continuando a seguire le linee guida e le limitazioni di REST e della specifica FHIR. Per raggiungere questo obiettivo, la ricerca FHIR ha le seguenti proprietà:

  • Il totale della ricerca è una stima fino al ritorno dell'ultima pagina. I risultati di ricerca restituiti dal metodo fhir.search includono il totale della ricerca (la proprietà Bundle.total), che corrisponde al numero totale di corrispondenze nella ricerca. Il totale della ricerca è una stima fino a quando non viene restituita l'ultima pagina dei risultati di ricerca. Il totale della ricerca restituito con l'ultima pagina dei risultati è una somma accurata di tutte le corrispondenze della ricerca.

  • I risultati di ricerca forniscono un'impaginazione sequenziale e in avanti. Quando vengono restituiti più risultati di ricerca, la risposta include un URL di impaginazione (Bundle.link.url) per visualizzare la pagina dei risultati successiva.

Casi d'uso di base

La ricerca FHIR fornisce soluzioni per i seguenti casi d'uso:

Consulta le sezioni seguenti per le possibili soluzioni per questi casi d'uso.

Sfoglia in sequenza

Puoi creare un'applicazione a bassa latenza che consenta all'utente di sfogliare in avanti le pagine dei risultati in sequenza finché non trova la corrispondenza che cerca. Questa soluzione è possibile se il numero di corrispondenze è sufficientemente ridotto da consentire all'utente di trovare quella desiderata sfogliando pagina per pagina senza saltare i risultati. Se il tuo caso d'uso richiede agli utenti di spostarsi avanti di più pagine alla volta o di spostarsi indietro, consulta Passare a una pagina nelle vicinanze.

Questa soluzione non può fornire un totale di ricerca accurato fino a quando non viene restituita l'ultima pagina dei risultati. Tuttavia, può fornire un totale approssimativo della ricerca con ogni pagina di risultati. Sebbene un totale di ricerche precise possa essere un requisito per un processo in background, un totale approssimativo della ricerca è in genere sufficiente per un utente umano.

Flusso di lavoro

Ecco un esempio di flusso di lavoro per questa soluzione:

  1. Un'app chiama il metodo fhir.search, che restituisce la prima pagina dei risultati di ricerca. La risposta include un URL di impaginazione (Bundle.link.url) se vengono restituiti più risultati. La risposta include anche il totale della ricerca (Bundle.total). Se i risultati da restituire sono più numerosi rispetto alla risposta iniziale, il totale della ricerca è solo una stima. Per saperne di più, vedi Impaginazione e ordinamento.

  2. L'app mostra la pagina dei risultati di ricerca, un link alla pagina successiva dei risultati (se disponibile) e il totale della ricerca.

  3. Se l'utente vuole visualizzare la pagina successiva dei risultati, fa clic sul link, generando una chiamata all'URL di impaginazione. La risposta include un nuovo URL di impaginazione se devono essere restituiti più risultati. La risposta include anche il totale della ricerca. Questa è una stima aggiornata se ci sono più risultati da restituire.

  4. L'app mostra la nuova pagina dei risultati di ricerca, un link alla pagina successiva dei risultati (se disponibile) e il totale della ricerca.

  5. I due passaggi precedenti vengono ripetuti finché l'utente non interrompe la ricerca o non viene restituita l'ultima pagina dei risultati.

Best practice

Scegli dimensioni della pagina adatte a un utente che possa leggere senza difficoltà. A seconda del tuo caso d'uso, potrebbero essere presenti da 10 a 20 corrispondenze per pagina. Le pagine più piccole si caricano più velocemente e un utente può avere difficoltà a gestire troppi link in una pagina. Puoi controllare le dimensioni della pagina con il parametro _count.

Elaborare un insieme di risultati di ricerca

Puoi ottenere una serie di risultati di ricerca effettuando chiamate successive al metodo fhir.search utilizzando l'URL di impaginazione. Se il numero di risultati di ricerca è abbastanza basso, puoi ottenere un insieme completo di risultati continuando finché non ci sono più pagine da restituire. Un totale accurato delle ricerche è incluso nell'ultima pagina dei risultati. Dopo aver ricevuto i risultati di ricerca, l'app può leggerli ed eseguire qualsiasi operazione di elaborazione, analisi o aggregazione di cui hai bisogno.

Tieni presente che se hai un numero molto elevato di risultati di ricerca, potrebbe non essere possibile ottenere l'ultima pagina dei risultati di ricerca (e il totale preciso dei risultati di ricerca) in un breve lasso di tempo.

Flusso di lavoro

Ecco un esempio di flusso di lavoro per questa soluzione:

  1. L'app chiama il metodo fhir.search, che restituisce la prima pagina dei risultati di ricerca. La risposta include un URL di impaginazione (Bundle.link.url) se vengono restituiti più risultati.

  2. Se vengono restituiti più risultati, l'app chiama l'URL di impaginazione del passaggio precedente per ottenere la pagina successiva dei risultati di ricerca.

  3. L'app ripete il passaggio precedente finché non ci sono altri risultati da restituire o finché non viene raggiunto un altro limite predefinito. Se raggiungi l'ultima pagina dei risultati di ricerca, il totale della ricerca è accurato.

  4. L'app elabora i risultati di ricerca.

A seconda del tuo caso d'uso, puoi eseguire una delle seguenti operazioni:

  • Attendi di aver ricevuto tutti i risultati di ricerca prima di elaborare i dati.
  • Elabora i dati ricevuti a ogni chiamata successiva al numero fhir.search.
  • Imposta un tipo di limite, ad esempio il numero di corrispondenze restituite o la quantità di tempo trascorso. Quando viene raggiunto il limite, puoi elaborare i dati, non elaborarli o eseguire altre azioni.

Opzioni di design

Ecco alcune opzioni di progettazione che potrebbero ridurre la latenza di ricerca:

  • Imposta dimensioni di pagina grandi. Usa il parametro _count per impostare dimensioni di pagina grandi, ad esempio da 500 a 1000, a seconda del caso d'uso. L'utilizzo di pagine di dimensioni maggiori aumenta la latenza per il recupero di ogni pagina, ma potrebbe velocizzare il processo complessivo, dal momento che sono necessari meno recuperi di pagina per ottenere l'intero set di risultati di ricerca.

  • Limitare i risultati di ricerca. Se hai bisogno solo di un totale accurato per la ricerca (non è necessario restituire il contenuto della risorsa), imposta il parametro _elements del metodo fhir.search su identifier. Ciò potrebbe ridurre la latenza della query di ricerca rispetto alla richiesta di restituzione delle risorse FHIR complete. Per ulteriori informazioni, consulta Limitazione dei campi restituiti nei risultati di ricerca.

Casi d'uso che richiedono il precaricamento e la memorizzazione nella cache

Potresti aver bisogno di funzionalità che vanno oltre il possibile utilizzando il semplice meccanismo di chiamata successiva al metodo fhir.search utilizzando gli URL di impaginazione. Una possibilità è creare un livello di memorizzazione nella cache tra l'app e l'archivio FHIR per mantenere lo stato della sessione durante il precaricamento e la memorizzazione nella cache dei risultati di ricerca. L'app può raggruppare i risultati di ricerca in piccole "pagine dell'app" con 10 o 20 corrispondenze. L'app può quindi pubblicare rapidamente queste piccole pagine dell'app per l'utente in modo diretto e non sequenziale, in base alle selezioni dell'utente. Consulta Accedere a una pagina nelle vicinanze per un esempio di questo tipo di flusso di lavoro.

Puoi creare una soluzione a bassa latenza che consente a un utente di attraversare un gran numero di risultati di ricerca finché non trova la corrispondenza che sta cercando. È in grado di scalare fino a un numero praticamente illimitato di corrispondenze, mantenendo bassa la latenza e comportando un aumento relativamente ridotto del consumo di risorse. Un utente può andare direttamente a una pagina dei risultati di ricerca, fino a un numero prestabilito di pagine avanti o indietro rispetto alla pagina corrente. Puoi fornire una stima del totale delle ricerche con ogni pagina di risultati. Come riferimento, questo design è simile a quello della Ricerca Google.

Flusso di lavoro

La Figura 1 mostra un flusso di lavoro di esempio per questa soluzione. Con questo flusso di lavoro, ogni volta che l'utente seleziona una pagina di risultati da visualizzare, l'app fornisce link alle pagine nelle vicinanze. In questo caso, l'app fornisce link a pagine fino a cinque pagine a ritroso rispetto alla pagina selezionata e fino a quattro pagine in avanti dalla pagina selezionata. Per rendere visibili le quattro pagine di inoltro, l'app precarica 40 corrispondenze aggiuntive quando l'utente seleziona una pagina di risultati.

di precaricamento e cache

Figura 1. L'app raggruppa i risultati di ricerca in "pagine dell'app" che vengono memorizzate nella cache e rese disponibili all'utente.

La figura 1 illustra questi passaggi:

  1. L'utente inserisce una query di ricerca nel frontend dell'app, avviando le seguenti azioni:

    1. L'app chiama il metodo fhir.search per precaricare la prima pagina dei risultati di ricerca.

      Il parametro _count è impostato su 100 per mantenere le dimensioni della pagina della risposta relativamente ridotte, con conseguente tempi di risposta relativamente rapidi. La risposta include un URL di impaginazione (Bundle.link.url) se vengono restituiti più risultati. La risposta include anche il totale della ricerca (Bundle.total). Il totale della ricerca è una stima se vengono restituiti più risultati. Per ulteriori informazioni, consulta Impaginazione e ordinamento.

    2. L'app invia la risposta al livello di memorizzazione nella cache.

  2. Nel livello di memorizzazione nella cache, l'app raggruppa le 100 corrispondenze della risposta in 10 pagine dell'app con 10 corrispondenze. La pagina dell'app è un piccolo raggruppamento di corrispondenze che l'app può mostrare all'utente.

  3. L'app mostra all'utente la pagina 1 dell'app. La pagina 1 dell'app include i link alle pagine 2-10 dell'app e il totale stimato della ricerca.

  4. L'utente fa clic su un link a un'altra pagina dell'app (in questo esempio, pagina 10), avviando le seguenti azioni:

    1. L'app chiama il metodo fhir.search, utilizzando l'URL di impaginazione restituito con il precaricamento precedente, per precaricare la pagina successiva dei risultati di ricerca.

      Il parametro _count è impostato su 40 per precaricare le successive 40 corrispondenze dalla query di ricerca dell'utente. Le 40 corrispondenze si riferiscono alle successive quattro pagine dell'app rese disponibili all'utente dall'app.

    2. L'app invia la risposta al livello di memorizzazione nella cache.

  5. Nel livello di memorizzazione nella cache, l'app raggruppa le 40 corrispondenze della risposta in quattro pagine dell'app con 10 corrispondenze.

  6. L'app mostra all'utente la pagina 10. La pagina 10 dell'app include link alle pagine 5-9 dell'app (le cinque pagine a ritroso dalla pagina 10 dell'app) e link alle pagine 11-14 (le quattro pagine dell'app a partire dalla pagina 10). La pagina 10 dell'app include anche il totale stimato delle ricerche.

Questa operazione può continuare finché l'utente vuole continuare a fare clic sui link alle pagine dell'app. Tieni presente che se l'utente torna indietro dalla pagina corrente dell'app e hai già memorizzato tutte le pagine dell'app nelle vicinanze nella cache, puoi scegliere di non eseguire un nuovo precaricamento, a seconda del caso d'uso.

Questa soluzione è veloce ed efficiente per i seguenti motivi:

  • I piccoli precaricamenti e le pagine delle app ancora più piccole vengono elaborati rapidamente.
  • I risultati di ricerca memorizzati nella cache riducono la necessità di effettuare più chiamate per gli stessi risultati.
  • Il meccanismo rimane veloce indipendentemente da quanto sia elevato il numero di risultati di ricerca.

Opzioni di design

Ecco alcune opzioni di progettazione da prendere in considerazione, a seconda del caso d'uso:

  • Dimensioni della pagina dell'app. Le pagine della tua app possono contenere più di 10 corrispondenze, se sono adatte al tuo caso d'uso. Tieni presente che le pagine più piccole si caricano più velocemente e che un utente può gestire troppi link in una pagina.

  • Numero di link alle pagine dell'app. Nel flusso di lavoro suggerito qui, ogni pagina dell'app restituisce nove link ad altre pagine dell'app: cinque link alle pagine dell'app direttamente a ritroso dalla pagina corrente dell'app e quattro link che rimandano alle pagine direttamente dalla pagina corrente dell'app. Puoi modificare questi valori per adattarli al tuo caso d'uso.

best practice

  • Utilizza il livello di memorizzazione nella cache solo se necessario. Se imposti un livello di memorizzazione nella cache, utilizzalo solo quando il tuo caso d'uso lo richiede. Le ricerche che non richiedono il livello di memorizzazione nella cache dovrebbero ignorarlo.

  • Riduci le dimensioni della cache. Per risparmiare risorse, puoi ridurre le dimensioni della cache eliminando i vecchi risultati di ricerca, mantenendo al contempo gli URL della pagina utilizzati per ottenerli. Puoi quindi ricostruire la cache come necessario richiamando gli URL delle pagine. Tieni presente che i risultati di più chiamate allo stesso URL di impaginazione possono cambiare nel tempo, poiché le risorse nell'archivio FHIR vengono create, aggiornate ed eliminate in background. L'eliminazione definitiva, la modalità di eliminazione definitiva e la frequenza di eliminazione della cache sono decisioni di progettazione che dipendono dal caso d'uso specifico.

  • Svuotare la cache per una determinata ricerca. Per risparmiare risorse, puoi rimuovere completamente dalla cache i risultati delle ricerche inattive. Valuta la possibilità di rimuovere prima le ricerche non attive più lunghe. Tieni presente che se una ricerca eliminata diventa nuovamente attiva, potrebbe verificarsi uno stato di errore che forza il livello di memorizzazione nella cache a riavviare la ricerca.

Se vuoi che un utente sia in grado di passare a qualsiasi pagina nei risultati di ricerca, non solo alle pagine vicine a quella corrente, puoi utilizzare un livello di memorizzazione nella cache simile a quello descritto nella sezione Navigazione in una pagina vicina. Tuttavia, per consentire a un utente di accedere a qualsiasi pagina dei risultati di ricerca dell'app, dovrai precaricare e memorizzare nella cache tutti i risultati di ricerca. Con un numero relativamente ridotto di risultati di ricerca, questo è possibile. Con un numero molto elevato di risultati di ricerca, potrebbe essere impossibile, se non addirittura impossibile, precaricarli tutti. Nonostante un numero ridotto di risultati di ricerca, il tempo necessario per precaricarli può essere più lungo di quanto sia ragionevole aspettarsi che un utente li restituisca.

Flusso di lavoro

Configura un flusso di lavoro simile a Vai a una pagina nelle vicinanze, con questa differenza fondamentale: l'app continua a precaricare i risultati di ricerca in background finché non vengono restituite tutte le corrispondenze o non viene raggiunto un altro limite predefinito.

Ecco un esempio di flusso di lavoro per questa soluzione:

  1. L'app chiama il metodo fhir.search per precaricare la prima pagina dei risultati di ricerca dalla query di ricerca dell'utente. La risposta include un URL di impaginazione (Bundle.link.url) se vengono restituiti più risultati. La risposta include anche il totale della ricerca (Bundle.total). Si tratta di una stima se devono restituire più risultati.

  2. L'app raggruppa le corrispondenze della risposta in pagine dell'app di 20 corrispondenze e le archivia nella cache. La pagina dell'app è un piccolo gruppo di corrispondenze che l'app può mostrare all'utente.

  3. L'app mostra all'utente la prima pagina dell'app. La pagina dell'app include i link alle pagine dell'app memorizzate nella cache e il totale stimato delle ricerche.

  4. Se vengono restituiti altri risultati, l'app procede nel seguente modo:

    • Chiama l'URL di impaginazione restituito dal precaricamento precedente per ottenere la pagina successiva dei risultati di ricerca.
    • Raggruppa le corrispondenze della risposta in pagine dell'app con 20 corrispondenze e le archivia nella cache.
    • Aggiorna la pagina dell'app che l'utente sta attualmente visualizzando con nuovi link alle pagine dell'app appena precaricate e memorizzate nella cache.
  5. L'app ripete il passaggio precedente finché non ci sono altri risultati da restituire o finché non viene raggiunto un altro limite predefinito. L'ultima pagina dei risultati di ricerca restituisce un totale preciso delle ricerche.

Durante il precaricamento dell'app e le corrispondenze nella cache in background, l'utente può continuare a fare clic sui link alle pagine memorizzate nella cache.

Opzioni di design

Ecco alcune opzioni di progettazione da prendere in considerazione, a seconda del caso d'uso:

  • Dimensioni della pagina dell'app. Le pagine della tua app possono contenere più o meno di 20 corrispondenze, se sono adatte al tuo caso d'uso. Tieni presente che le pagine più piccole vengono caricate più velocemente e un numero eccessivo di link in una pagina può essere difficile da gestire per un utente.

  • Aggiorna il totale della ricerca. Mentre la tua app esegue il precaricamento e la memorizzazione nella cache dei risultati di ricerca in background, puoi mostrare all'utente totali delle ricerche sempre più precisi. Per farlo, configura l'app in modo da:

    • A un intervallo impostato, ottieni il totale della ricerca (la proprietà Bundle.total) dall'ultimo precaricamento nel livello di memorizzazione nella cache. Questa è la stima attuale migliore del totale delle ricerche. Mostra all'utente il totale della ricerca per indicare che si tratta di una stima. Determina la frequenza di questo aggiornamento in base al tuo caso d'uso.

    • Riconoscere quando il totale della ricerca del livello di memorizzazione nella cache è accurato. In altre parole, il totale della ricerca proviene dall'ultima pagina dei risultati di ricerca. Quando viene raggiunta l'ultima pagina dei risultati di ricerca, l'app mostra il totale della ricerca e indica all'utente che il totale della ricerca è accurato. L'app smette quindi di recuperare i totali delle ricerche dal livello di memorizzazione nella cache.

    Tieni presente che con un numero elevato di corrispondenze, il precaricamento in background e la memorizzazione nella cache potrebbero non raggiungere l'ultima pagina dei risultati di ricerca (e il totale accurato della ricerca) prima che l'utente completi la sessione di ricerca.

best practice

  • Deduplica le risorse incluse. Se utilizzi i parametri _include e _revinclude per il precaricamento e la memorizzazione nella cache dei risultati di ricerca, ti consigliamo di deduplicare le risorse incluse nella cache dopo ogni precaricamento. Questo ti aiuterà a risparmiare memoria riducendo la dimensione della cache. Quando raggruppi le corrispondenze nelle pagine dell'app, aggiungi le risorse incluse appropriate a ogni pagina dell'app. Per ulteriori informazioni, consulta Inclusione di risorse aggiuntive nei risultati di ricerca.

  • Imposta un limite per il precaricamento e la memorizzazione nella cache. Con un numero molto elevato di risultati di ricerca, potrebbe essere impossibile, se non addirittura impossibile, precaricarli tutti. Consigliamo di impostare un limite per il numero di risultati di ricerca da precaricare. In questo modo le dimensioni della cache sono gestibili e puoi risparmiare memoria. Ad esempio, potresti limitare le dimensioni della cache a 10.000 o 20.000 corrispondenze. In alternativa, puoi limitare il numero di pagine da precaricare o impostare un limite di tempo dopo il quale il precaricamento si interrompe. Il tipo di limite che imponi e il modo in cui lo imponi sono decisioni di progettazione che dipendono dal tuo caso d'uso. Se il limite viene raggiunto prima che vengano restituiti tutti i risultati di ricerca, puoi indicarlo all'utente, indicando che il totale della ricerca è ancora una stima.

Memorizzazione nella cache di frontend

Il frontend dell'applicazione, ad esempio un browser web o un'app mobile, può fornire una memorizzazione dei risultati di ricerca nella cache come alternativa all'introduzione di un livello di memorizzazione nella cache nell'architettura. Questo approccio può consentire di passare alla pagina precedente o a qualsiasi pagina della cronologia di navigazione, sfruttando le chiamate AJAX e memorizzando i risultati di ricerca e/o gli URL di impaginazione. Ecco alcuni vantaggi di questo approccio:

  • Può richiedere meno risorse rispetto a un livello di memorizzazione nella cache.
  • È più scalabile, in quanto distribuisce il lavoro di memorizzazione nella cache tra molti client.
  • È più facile determinare quando le risorse memorizzate nella cache non sono più necessarie, ad esempio quando l'utente chiude una scheda o esce dall'interfaccia di ricerca.

Best practice generali

Di seguito sono riportate alcune best practice che si applicano a tutte le soluzioni in questo documento.

  • Pensa a pagine di dimensioni inferiori al valore _count. In alcune circostanze, una ricerca potrebbe restituire pagine contenenti meno corrispondenze rispetto al valore _count specificato. Ad esempio, questo può accadere se specifichi una dimensione di pagina particolarmente grande. Se la ricerca restituisce una pagina inferiore al valore _count e la tua app utilizza un livello di memorizzazione nella cache, potrebbe essere necessario decidere se (1) visualizzare meno risultati del previsto sulla pagina di un'app oppure (2) recuperare qualche risultato in più per ottenere un numero sufficiente di risultati per una pagina completa dell'app. Per ulteriori informazioni, consulta Impaginazione e ordinamento.

  • Riprovare per gli errori di richiesta HTTP non riprovabile. La tua app dovrebbe aspettarsi errori di richieste HTTP non irreversibili, come 429 o 500, e riprovare dopo averli ricevuti.

Valutare i casi d'uso

L'implementazione di funzionalità come la navigazione a qualsiasi pagina, l'ottenimento di totali delle ricerche precisi e l'aggiornamento dei totali stimati aumentano la complessità e i costi di sviluppo dell'app. Queste funzionalità possono anche aumentare la latenza e i costi monetari per l'utilizzo delle risorse Google Cloud. Ti consigliamo di valutare attentamente i tuoi casi d'uso per assicurarti che il valore di queste funzionalità giustifica i costi. Ecco alcuni aspetti da considerare:

  • Navigazione in qualsiasi pagina. In genere un utente non ha bisogno di accedere a una pagina specifica, ma molte pagine dalla pagina corrente. Nella maggior parte dei casi, visitare una pagina vicina è sufficiente.

  • Totali di ricerca precisi. I totali delle ricerche possono variare man mano che le risorse nell'archivio FHIR vengono create, aggiornate ed eliminate. Per questo motivo, un totale accurato delle ricerche è preciso nel momento in cui viene restituito (con l'ultima pagina dei risultati di ricerca), ma nel tempo potrebbe non rimanere preciso. Di conseguenza, totali di ricerca accurati potrebbero avere un valore limitato per la tua app, a seconda del tuo caso d'uso.