API Search per servizi in bundle legacy

L'API Search fornisce un modello per l'indicizzazione dei documenti che contengono dati strutturati. Puoi cercare in un indice organizzare e presentare i risultati di ricerca. L'API supporta la corrispondenza del testo completo nei campi di stringa. I documenti e gli indici vengono salvati in un archivio permanente distinto ottimizzato per le operazioni di ricerca. L'API Search può indicizzare un numero qualsiasi di documenti. Datastore di App Engine potrebbe essere più appropriato per le applicazioni che devono recuperare set di risultati molto grandi. Per visualizzare dei contenuti del pacchetto search, consulta Riferimento pacchetto search.

Panoramica

L'API Search si basa su quattro concetti principali: documenti, indici, query e che consentono di analizzare i dati e visualizzare i risultati.

Documenti

Un documento è un oggetto con un ID univoco e un elenco di campi contenenti i dati dell'utente. Ogni campo ha un nome e un tipo. Esistono diversi tipi di campi: identificati dai tipi di valori che contengono:

  • Campo Atom: una stringa di caratteri indivisibile.
  • Campo di testo: una stringa di testo normale in cui è possibile eseguire ricerche parola per parola.
  • Campo HTML: una stringa contenente tag di markup HTML. È possibile eseguire ricerche solo nel testo al di fuori dei tag di markup.
  • Campo numerico: un numero con virgola mobile.
  • Campo Tempo: un valore time.Time, che viene memorizzato con una precisione in millisecondi.
  • Campo punto geografico: un oggetto dati con coordinate di latitudine e longitudine.

La dimensione massima di un documento è 1 MB.

Indici

Un indice archivia i documenti per il recupero. Puoi recuperare un singolo documento tramite il relativo ID, un intervallo di documenti con ID consecutivi o tutti i documenti di un indice. Puoi anche cercare in un indice per recuperare documenti che soddisfano una criteri sui campi e sui relativi valori, specificati come stringa di query. Puoi gestire gruppi di documenti inserendoli in indici separati.

Non c'è limite al numero di documenti in un indice o al numero di che puoi utilizzare. La dimensione totale di tutti i documenti in un singolo indice è è limitato a 10 GB per impostazione predefinita. Gli utenti con il ruolo Amministratore App Engine possono inviare una richiesta dalla pagina App Engine Search della console Google Cloud per aumentare le dimensioni fino a 200 GB.

Query

Per eseguire una ricerca in un indice, devi creare una query, che contiene una stringa di query e possibilmente alcune opzioni aggiuntive. Una stringa di query specifica le condizioni per i valori di uno o più campi del documento. Quando cerchi un indice, vengono restituiti solo quelli documenti nell'indice con campi che soddisfano la query.

La query più semplice, a volte chiamata "ricerca globale", è una stringa che contiene solo valori di campo. Questa ricerca utilizza una stringa che cerca i documenti che contengono le parole "rosa" e "acqua":

index.Search(ctx, "rose water", nil)

che cerca i documenti con campi che contengono la data 4 luglio 1776 o campi di testo che includono la stringa "1776-07-04":

index.Search(ctx, "1776-07-04", nil)

Una stringa di query può anche essere più specifica. Può contenere uno o più termini, ciascuno che indica un campo e una limitazione del valore del campo. La forma esatta di un termine dipende dal tipo di campo. Ad esempio, supponendo che esista un campo di testo chiamato "Prodotto" e un campo numerico chiamato "Prezzo", di seguito è riportata una stringa di query con due termini:

// search for documents with pianos that cost less than $5000
index.Search(ctx, "Product = piano AND Price < 5000", nil)

Le opzioni di query, come suggerisce il nome, non sono obbligatorie. Consentono una varietà di caratteristiche:

  • Controlla il numero di documenti restituiti nei risultati di ricerca.
  • Specifica quali campi del documento includere nei risultati. L'impostazione predefinita è includere tutti i campi del documento originale. Puoi specificare che i risultati includano solo un sottoinsieme di campi (il documento originale non è interessato).
  • Ordina i risultati.
  • Creare "campi calcolati" per i documenti con FieldExpressions e i campi di testo ridotti snippet.
  • È possibile scorrere le pagine nei risultati di ricerca restituendo solo una parte dei documenti corrispondenti in ogni query (utilizzando offset e cursori)

Ti consigliamo di registrare le stringhe di query nella tua applicazione se vuoi conservare un record delle query eseguite.

Risultati di ricerca

Una chiamata Search restituisce un valore Iterator, che può essere utilizzato per restituire l'insieme completo di documenti corrispondenti.

Materiale di formazione aggiuntivo

Oltre a questa documentazione, puoi leggere corso di formazione in due parti sull'API Search all'indirizzo Google Developer's Academy. Sebbene il corso utilizzi l'API Python, potresti trovare utile la discussione aggiuntiva dei concetti di ricerca.

Documenti e campi

I documenti sono rappresentati da strutture Go, che contengono un elenco di campi. I documenti possono essere rappresentati anche da qualsiasi tipo che implementa l'interfaccia FieldLoadSaver.

Identificatore documento

Ogni documento in un indice deve avere un identificatore univoco, ovvero docID. L'identificatore può essere utilizzato per recuperare un documento da un indice senza eseguire una ricerca. Per impostazione predefinita, l'API Search genera automaticamente un docID quando viene creato un documento. Puoi anche specificare il docID autonomamente quando crei un documento. Un docID deve contenere solo caratteri ASCII visibili e stampabili (codici ASCII da 33 a 126 inclusi) e non deve superare i 500 caratteri. Un identificatore di documento non può iniziare con un punto esclamativo ("!") e non può iniziare e terminare con trattini bassi doppi ("__").

Sebbene sia pratico creare identificatori di documenti univoci leggibili e significativi, non puoi includere docID in una ricerca. Considera questo scenario: hai un indice con documenti che rappresentano componenti, utilizzando il numero di serie del componente come docID. Sarà molto efficiente recuperare il documento per ogni singola parte, ma sarà impossibile cercare un intervallo di numeri di serie insieme ad altri valori di campo, come la data di acquisto. Il problema viene risolto memorizzando il numero di serie in un campo atom.

Campi documento

Un documento contiene campi con un nome, un tipo e un singolo valore di quel tipo. Due o più campi possono avere lo stesso nome, ma tipi diversi. Ad esempio, puoi definire due campi con il nome "età": uno con un tipo di testo (valore "ventidue") e l'altro con un tipo di numero (valore 22).

Nomi dei campi

I nomi dei campi sono sensibili alle maiuscole e possono contenere solo caratteri ASCII. Devono iniziare con una lettera e possono contenere lettere, cifre o trattini bassi. Nome di un campo non può contenere più di 500 caratteri.

Campi con più valori

Un campo può contenere un solo valore, che deve corrispondere al tipo di campo. I nomi dei campi non devono essere univoci. Un documento può avere più campi con lo stesso nome e lo stesso tipo, un modo per rappresentare un campo con più valori. Tuttavia, i campi di date e numeri con lo stesso nome non possono essere ripetuti. Un documento può anche contenere più campi con lo stesso nome e tipi di campi diversi.

Tipi di campo

Esistono tre tipi di campi che memorizzano stringhe di caratteri. Li chiamiamo collettivamente campi di stringa:

  • Campo di testo: una stringa con una lunghezza massima di 1024**2 caratteri.
  • Campo HTML: una stringa in formato HTML con lunghezza massima di 1024**2 caratteri.
  • Campo atomo: una stringa con una lunghezza massima di 500 caratteri.

Esistono anche tre tipi di campi per l'archiviazione di dati non testuali:

  • Campo numerico: un valore in virgola mobile a doppia precisione compreso tra -2147483647 e 2147483647.
  • Campo Tempo: un valore time.Time, memorizzato con una precisione di millisecondi.
  • Campo punti geografici: un punto sulla Terra descritto da latitudine e longitudine coordinate.

I tipi di campi stringa sono integrati Tipo di string e search HTML e Tipi di Atom. I campi numerici vengono rappresentati con il tipo integrato di Go float64, i campi di tempo utilizzano il tipo time.Time e i campi geopoint utilizzano il tipo GeoPoint del pacchetto appengine.

Trattamento speciale dei campi di stringhe e ora

Quando un documento include ora, testo I campi HTML vengono aggiunti a un indice; viene effettuata una gestione speciale. È utile a capire cosa sta succedendo "in background" per utilizzare l'API Search in modo efficace.

Tokenizzazione dei campi stringa

Quando un campo HTML o di testo viene indicizzato, i relativi contenuti vengono tokenizzati. La stringa è suddiviso in token, indipendentemente dal fatto che gli spazi vuoti o i caratteri speciali (segni di punteggiatura, segni di cancelletto, barra rovesciata e così via). L'indice includerà una voce per ogni token. In questo modo puoi cercare parole chiave e frasi che includono solo una parte del valore di un campo. Ad esempio, la ricerca di "scuro" che associa un documento a un campo di testo contenente la stringa "it was a dark and notte tempestosa" e la ricerca di "tempo" corrisponderà a un documento con un campo di testo contenente la stringa "this is a real-time system".

Nei campi HTML, il testo all'interno dei tag markup non viene tokenizzato, pertanto un documento con un campo HTML contenente it was a <strong>dark</strong> night corrisponderà a una ricerca di "notte", ma non di "forte". Se vuoi poter cercare di markup, memorizzalo in un campo di testo.

I campi di atomi non vengono tokenizzati. Un documento con un campo atomico che ha il valore "maltempo" corrisponderà solo alla ricerca dell'intera stringa "maltempo". Non corrisponderà a una ricerca di "cattivo" o "meteo" da solo.

Regole di tokenizzazione
  • Il trattino basso (_) e la e commerciale (&) non suddividono le parole in di token.

  • Questi caratteri di spaziatura suddividono sempre le parole in token: spazio, ritorno a capo, avanzamento riga, tabulazione orizzontale, tabulazione verticale, a capo di modulo e NULL.

  • Questi caratteri vengono considerati come segni di punteggiatura e suddividono le parole in token:

    !"%()
    *,-|/
    []]^`
    :=>?@
    {}~$
  • I caratteri nella tabella seguente in genere suddividono le parole in token, ma possono essere gestiti in modo diverso a seconda del contesto in cui appaiono:

    Basato su caratteri Regola
    < In un campo HTML il valore "minore di" indica l'inizio di un tag HTML che viene ignorato.
    + Una stringa composta da uno o più "plus" vengono trattati come parte della parola se compare alla fine della parola (C++).
    # L'"hash" viene trattato come parte della parola se è preceduta da a, b, c, d, e, f, g, j o x (a# - g# sono note musicali; j# e x# sono linguaggio di programmazione, c# sono entrambi). Se un termine è preceduto da "#" (#google), viene considerato un hashtag e il cancelletto diventa parte della parola.
    ' L'apostrofo è una lettera se precede la lettera "s" seguito da un'interruzione di parola, come in "John's hat".
    . Se tra le cifre compare una virgola decimale, questo fa parte di un numero (ovvero il separatore decimale). Può anche essere parte di una parola se utilizzata in un acronimo (A.B.C).
    - Il trattino fa parte di una parola se usato in un acronimo (I-B-M).
  • Tutti gli altri caratteri a 7 bit, tranne lettere e numeri ("A-Z", "a-z", "0-9") sono gestiti come punteggiatura e suddividono le parole in token.

  • Tutto il resto viene analizzato come carattere UTF-8.

Acronimi

La tokenizzazione utilizza regole speciali per riconoscere gli acronimi (stringhe come "I.B.M.", "a-b-c" o "C I A"). Un acronimo è una stringa di singoli caratteri alfabetici, con lo stesso carattere separatore tra tutti i caratteri. I separatori validi sono il punto, il trattino o un numero qualsiasi di spazi. Il carattere separatore viene rimosso dalla stringa quando un acronimo viene tokenizzato. Quindi le stringhe di esempio menzionate sopra diventano i token "ibm", "abc" e "cia". Il testo originale rimane nel campo del documento.

Quando si tratta di acronimi, tieni presente che:

  • Un acronimo non può contenere più di 21 lettere. Una stringa di acronimi valida con più di 21 lettere saranno suddivise in una serie di acronimi, ogni 21 lettere o meno.
  • Se le lettere di un acronimo sono separate da spazi, tutte le lettere devono essere in maiuscolo. Gli acronimi creati con punto e trattino possono usare lettere maiuscole e minuscole lettere.
  • Quando cerchi un acronimo, puoi inserire la relativa forma canonica (la stringa senza separatori) o l'acronimo con la punteggiatura preceduta dal carattere trattino o il punto (ma non entrambi) tra le lettere. Pertanto, il testo "I.B.M" potrebbe essere recuperato con uno qualsiasi dei termini di ricerca "I-B-M", "I.B.M" o "IBM".

Precisione del campo temporale

Quando crei un campo della data e dell'ora in un documento, imposta il relativo valore su un time.Time. Ai fini dell'indicizzazione e della ricerca nel campo della data e dell'ora, qualsiasi componente temporale viene ignorato e la data viene convertita nel numero di giorni dal 1/1/1970 UTC. Ciò significa che, anche se un campo ora può contenere un valore di ora preciso, una query sulla data può specificare solo un valore del campo ora nel formato yyyy-mm-dd. Ciò significa anche che l'ordine ordinato che i campi temporali con la stessa data sono non ben definiti. Mentre il tipo time.Time rappresenta il tempo con una precisione in nanosecondi, l'API Search li archivia con pochi millisecondi la precisione.

Altre proprietà del documento

Il ranking di un documento è un numero intero positivo che determina l'ordinamento predefinito dei documenti restituiti da una ricerca. Per impostazione predefinita, il ranking è impostato su l'ora di creazione del documento calcolata in secondi dal 1° gennaio, 2011. Puoi impostare esplicitamente il ranking quando crei un documento. Non è buona idea assegnare lo stesso ranking a molti documenti e non dovresti mai assegnare lo stesso ranking a più di 10.000 documenti. Se specifichi ordinare opzioni, puoi utilizzare il ranking come chiave di ordinamento. Tieni presente che quando il ranking viene utilizzato in un ordinamento espressione o un'espressione di campo viene indicato come _rank. Per ulteriori informazioni sull'impostazione del ranking, consulta la documentazione di riferimento DocumentMetadata.

La proprietà Language del Lo struct Field specifica la lingua in cui il campo è codificato.

Collegamento da un documento ad altre risorse

Puoi utilizzare l'docID e altri campi di un documento come link ad altri risorse nella tua applicazione. Ad esempio, se utilizzi Blobstore puoi associare il documento a un blob specifico impostando docID o il valore di un campo Atom sul BlobKey dei dati.

Creazione di un documento

Il seguente esempio di codice mostra come creare un oggetto documento. Il tipo User specifica la struttura del documento e viene creato un valore User nel modo in molti modi diversi.

import (
	"fmt"
	"net/http"
	"time"

	"golang.org/x/net/context"

	"google.golang.org/appengine"
	"google.golang.org/appengine/search"
)

type User struct {
	Name      string
	Comment   search.HTML
	Visits    float64
	LastVisit time.Time
	Birthday  time.Time
}

func putHandler(w http.ResponseWriter, r *http.Request) {
	id := "PA6-5000"
	user := &User{
		Name:      "Joe Jackson",
		Comment:   "this is <em>marked up</em> text",
		Visits:    7,
		LastVisit: time.Now(),
		Birthday:  time.Date(1960, time.June, 19, 0, 0, 0, 0, nil),
	}
	// ...

Utilizzo di un indice

Inserire i documenti in un indice

Quando inserisci un documento in un indice, il documento viene copiato nello spazio di archiviazione permanente e ciascuno dei suoi campi viene indicizzato in base al nome, al tipo e al valore docID.

Il seguente esempio di codice mostra come accedere a un indice e inserire un documento in li annotino.

// ...
ctx := appengine.NewContext(r)
index, err := search.Open("users")
if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
	return
}
_, err = index.Put(ctx, id, user)
if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
	return
}
fmt.Fprint(w, "OK")

Quando inserisci un documento in un indice che contiene già un documento con lo stesso docID, il nuovo documento sostituisce quello precedente. Non viene fornito alcun avviso. Puoi chiamare Index.Get prima di creare o aggiungere un documento a un indice per verificare se esiste già un docID specifico.

Il metodo Put restituisce un docID. Se non hai specificato il valore docID di persona, puoi esaminare il risultato per scoprire docID che è stato generato:

id, err = index.Put(ctx, "", user)
if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
	return
}
fmt.Fprint(w, id)

Tieni presente che la creazione di un'istanza di Index non garantisce che dell'indice permanente esistente. Un indice permanente viene creato la prima volta che lo aggiungi un documento con il metodo put.

Aggiornamento dei documenti

Un documento non può essere modificato dopo averlo aggiunto a un indice. Non puoi aggiungere o rimuovi campi o modifica il valore di un campo. Tuttavia, puoi sostituire il documento con un nuovo documento con lo stesso docID.

Recupero dei documenti tramite docID

Utilizza il metodo Index.Get per recuperare un documento da un indice tramite il relativo docID:

func getHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	index, err := search.Open("users")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	id := "PA6-5000"
	var user User
	if err := index.Get(ctx, id, &user); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprint(w, "Retrieved document: ", user)
}

Ricerca dei documenti in base ai contenuti

Per recuperare documenti da un indice, devi creare una stringa di query e richiamare Index.Search. Search restituisce un iteratore che genera i documenti corrispondenti in ordine decrescente di ranking.

func searchHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	index, err := search.Open("myIndex")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	for t := index.Search(ctx, "Product: piano AND Price < 5000", nil); ; {
		var doc Doc
		id, err := t.Next(&doc)
		if err == search.Done {
			break
		}
		if err != nil {
			fmt.Fprintf(w, "Search error: %v\n", err)
			break
		}
		fmt.Fprintf(w, "%s -> %#v\n", id, doc)
	}
}

Eliminazione di un indice

Ogni indice è composto da documenti indicizzati e da un schema dell'indice. Per eliminare un indice: eliminare tutti i documenti in un indice e poi eliminare lo schema dell'indice.

Puoi eliminare i documenti in un indice specificando il valore docID di il documento da eliminare con il metodo Index.Delete.

func deleteHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	index, err := search.Open("users")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	id := "PA6-5000"
	err = index.Delete(ctx, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprint(w, "Deleted document: ", id)
}

Coerenza finale

Quando inserisci, aggiorni o elimini un documento in un indice, la modifica si propaga in più data center. In genere l'operazione è rapida, ma il tempo necessario può variare. L'API Search garantisce che il termine coerenza. Ciò significa che in alcuni casi, una ricerca o il recupero di uno o più documenti potrebbe restituire risultati che non riflettono le modifiche più recenti.

Schemi indice

Ogni indice ha uno schema che mostra tutti i nomi e i tipi di campo che compaiono nei documenti che contiene. Non puoi definire uno schema autonomamente. Gli schemi vengono gestiti in modo dinamico; vengono aggiornate man mano che vengono aggiunti un indice. Uno schema semplice potrebbe essere simile al seguente, in formato JSON:

{'comment': ['TEXT'], 'date': ['DATE'], 'author': ['TEXT'], 'count': ['NUMBER']}

Ogni chiave del dizionario è il nome di un campo del documento. Il valore della chiave è un dei tipi di campo utilizzati con il nome di quel campo. Se hai utilizzato lo stesso nome di campo con tipi di campo diversi, lo schema elenca più di un tipo di campo per un nome di campo, ad esempio:

{'ambiguous-integer': ['TEXT', 'NUMBER', 'ATOM']}

Quando un campo compare in uno schema, non può mai essere rimosso. Non è possibile eliminare un campo, anche se l'indice non contiene più documenti con quel determinato nome di campo.

Uno schema non definisce una "classe" nel senso della programmazione di oggetti. Per quanto riguarda l'API Search, ogni documento è univoco e gli indici possono contenere diversi tipi di documenti. Se vuoi trattare raccolte di oggetti con lo stesso elenco di campi come istanze di una classe, devi applicare un'astrazione nel codice. Ad esempio, puoi assicurarti che tutti i documenti con lo stesso insieme di campi vengano conservati nel proprio indice. Lo schema dell'indice può essere visto come definizione della classe e ogni documento nell'indice è un'istanza per la classe.

Visualizzazione degli indici nella console Google Cloud

Nella console Google Cloud, puoi visualizzare informazioni sugli indici della tua applicazione e sui documenti che contengono. Se fai clic sul nome di un indice, vengono visualizzati i documenti che contiene. Vedrai tutti i campi dello schema definiti per l'indice. Per ogni documento con un campo con quel nome, vedrai il valore del campo. Puoi anche eseguire query sull'indice direttamente dalla console.

Quote dell'API Search

L'API Search ha diverse quote gratuite:

Risorsa o chiamata API Quota gratuita
Capacità di archiviazione totale (documenti e indici) 0,25 GB
Query 1000 query al giorno
Aggiunta di documenti agli indici 0,01 GB al giorno

L'API Search impone questi limiti per garantire l'affidabilità del servizio. Queste norme valgono per le app gratuite e a pagamento:

Risorsa Quota di sicurezza
Utilizzo massimo delle query 100 minuti aggregati di tempo di esecuzione della query al minuto
Numero massimo di documenti aggiunti o eliminati 15.000 al minuto
Dimensione massima per indice (numero illimitato di indici consentito) 10 GB

L'utilizzo dell'API viene conteggiato in modi diversi a seconda del tipo di chiamata:

  • Index.Search: ogni chiamata API viene conteggiata come una query; il tempo di esecuzione è equivalente alla latenza della chiamata.
  • Index.Put: quando aggiungi documenti agli indici, le dimensioni di ogni documento e il numero di documenti vengono conteggiati ai fini della quota di indicizzazione.
  • Tutte le altre chiamate all'API Search vengono conteggiate in base al numero di operazioni che comporta:
    • Index.Get: 1 operazione conteggiata per ogni documento effettivamente restituito o 1 operazione se non viene restituito nulla.
    • Index.Delete: 1 operazione conteggiata per ogni documento nella richiesta oppure 1 operazione se la richiesta è vuota.

La quota sul throughput delle query viene impostata in modo che un singolo utente non possa monopolizzare il servizio di ricerca. Poiché le query possono essere eseguite contemporaneamente, ogni applicazione è autorizzata a eseguire query che consumano fino a 100 minuti di tempo di esecuzione per un minuto di tempo reale. Se esegui molte query brevi, probabilmente non raggiungerai questo limite. Una volta superata la quota, le query successive non riusciranno fino alla sezione temporale successiva, quando la quota verrà ripristinata. La quota non viene impostata rigorosamente in intervalli di un minuto; viene utilizzata una variante dell'algoritmo bucket con perdite per controllare la larghezza di banda di ricerca in incrementi di cinque secondi.

Puoi trovare ulteriori informazioni sulle quote nella pagina Quote. Quando un'app tenta di superare questi importi, viene visualizzato un errore di quota insufficiente.

Tieni presente che, anche se questi limiti vengono applicati al minuto, nella console i totali giornalieri di ognuna. I clienti con assistenza Silver, Gold o Platinum possono richiedere limiti di velocità effettiva più elevati contattando il rappresentante dell'assistenza.

Prezzi dell'API Search

I seguenti addebiti vengono applicati all'utilizzo oltre le quote gratuite:

Risorsa Costo
Capacità di archiviazione totale (documenti e indici) $0,18 per GB al mese
Query 0,50 $ per 10.000 query
Indicizzazione dei documenti disponibili per la ricerca 2,00 $ per GB

Puoi trovare ulteriori informazioni sui prezzi nella pagina Prezzi.