软件包搜索为 App Engine 的搜索服务提供客户端。
基本运算
索引包含文档。每个索引均使用名称(即直观易懂的 ASCII 字符串)标识。
在索引中,文档与 ID 相关联,ID 也是直观易懂的 ASCII 字符串。文档的内容是从区分大小写的字段名称到值的映射。字段值的有效类型有:
- string,
- search.Atom,
- search.HTML,
- time.Time(以毫秒级精度存储),
- float64(介于 -2,147,483,647 和 2,147,483,647 之间的浮点值,含边界值),
- appengine.GeoPoint。
索引上的 Get 和 Put 方法会加载并保存文档。文档的内容通常用结构体指针表示。
示例代码:
type Doc struct { Author string Comment string Creation time.Time } index, err := search.Open("comments") if err != nil { return err } newID, err := index.Put(ctx, "", &Doc{ Author: "gopher", Comment: "the truth of the matter", Creation: time.Now(), }) if err != nil { return err }
单个文档可以通过其 ID 进行检索。将目标结构体传递给 Get 以保存生成的文档。
var doc Doc err := index.Get(ctx, id, &doc) if err != nil { return err }
搜索和列出文档
索引有两种方法可以同时检索多个文档:Search 和 List。
搜索查询索引将生成迭代器。与软件包数据存储区中的迭代器一样,将目标结构体传递给 Next 以解码下一个结果。当迭代器结束时,Next 将返回 Done。
for t := index.Search(ctx, "Comment:truth", nil); ; { var doc Doc id, err := t.Next(&doc) if err == search.Done { break } if err != nil { return err } fmt.Fprintf(w, "%s -> %#v\n", id, doc) }
Search 采用字符串查询来确定要返回的文档。查询可以很简单(例如要匹配的单个词),也可以很复杂。https://cloud.google.com/appengine/docs/standard/go/search/query_strings 中介绍了查询语言
Search 还采用可选的 SearchOptions 结构体,该结构体可以更好地控制结果的计算和返回方式。
调用 List 遍历索引中的所有文档。
for t := index.List(ctx, nil); ; { var doc Doc id, err := t.Next(&doc) if err == search.Done { break } if err != nil { return err } fmt.Fprintf(w, "%s -> %#v\n", id, doc) }
字段和构面
文档的内容可以用各种类型表示。这些通常是结构体指针,但它们也可以用实现 FieldLoadSaver 接口的任何类型表示。FieldLoadSaver 允许为 DocumentMetadata 类型的文档设置元数据。结构体指针的类型更强,更易于使用;FieldLoadSavers 更灵活。
文档的内容可以用两种方式表示:字段和构面。
字段是提供文档内容最常见的方式。字段可以存储多种类型的数据,并且可以使用查询字符串在搜索中进行匹配。
通过构面,您可以将分类信息附加到文档。唯一有效的构面类型是 search.Atom 和 float64。构面允许搜索结果包含搜索中匹配类别的摘要,并将搜索限制为仅匹配特定类别。
默认情况下,对于结构体指针,所有结构体字段都用作文档字段,使用的字段名称与结构体上的相同(因此必须以大写字母开头)。结构体字段可能具有 search:"name,options"
标记。名称必须以字母开头,并且仅由单词字符组成。“-”标记名称表示该字段将被忽略。如果选项为“facet”,则结构体字段将用作文档构面。如果选项为 "",则可以省略英文逗号。没有其他识别的选项。
示例代码:
// A and B are renamed to a and b. // A, C and I are facets. // D's tag is equivalent to having no tag at all (E). // F and G are ignored entirely by the search package. // I has tag information for both the search and json packages. type TaggedStruct struct { A float64 `search:"a,facet"` B float64 `search:"b"` C float64 `search:",facet"` D float64 `search:""` E float64 F float64 `search:"-"` G float64 `search:"-,facet"` I float64 `search:",facet" json:"i"` }
FieldLoadSaver 接口
文档的内容也可以用实现 FieldLoadSaver 接口的任何类型表示。此类型可以是但并非必须是结构体指针。搜索软件包将在加载文档内容时调用 Load,并在保存时调用 Save。除了 Field 的切片之外,Load 和 Save 方法还使用 DocumentMetadata 类型提供有关文档的其他信息(例如其 Rank 或 Facet 集)。此接口的可能用途包括派生非存储字段、验证字段或为字符串和 HTML 字段设置特定语言。
示例代码:
type CustomFieldsExample struct { // Item's title and which language it is in. Title string Lang string // Mass, in grams. Mass int } func (x *CustomFieldsExample) Load(fields []search.Field, meta *search.DocumentMetadata) error { // Load the title field, failing if any other field is found. for _, f := range fields { if f.Name != "title" { return fmt.Errorf("unknown field %q", f.Name) } s, ok := f.Value.(string) if !ok { return fmt.Errorf("unsupported type %T for field %q", f.Value, f.Name) } x.Title = s x.Lang = f.Language } // Load the mass facet, failing if any other facet is found. for _, f := range meta.Facets { if f.Name != "mass" { return fmt.Errorf("unknown facet %q", f.Name) } m, ok := f.Value.(float64) if !ok { return fmt.Errorf("unsupported type %T for facet %q", f.Value, f.Name) } x.Mass = int(m) } return nil } func (x *CustomFieldsExample) Save() ([]search.Field, *search.DocumentMetadata, error) { fields := []search.Field{ {Name: "title", Value: x.Title, Language: x.Lang}, } meta := &search.DocumentMetadata{ Facets: { {Name: "mass", Value: float64(x.Mass)}, }, } return fields, meta, nil }
变量
ErrInvalidDocumentType、ErrNoSuchDocument、ErrTooManyDocuments
var (
// ErrInvalidDocumentType is returned when methods like Put, Get or Next
// are passed a dst or src argument of invalid type.
ErrInvalidDocumentType = errors.New("search: invalid document type")
// ErrNoSuchDocument is returned when no document was found for a given ID.
ErrNoSuchDocument = errors.New("search: no such document")
// ErrTooManyDocuments is returned when the user passes too many documents to
// PutMulti or DeleteMulti.
ErrTooManyDocuments = fmt.Errorf("search: too many documents given to put or delete (max is %d)", maxDocumentsPerPutDelete)
)
完成
查询迭代完成时将返回 Done。
函数
func LoadStruct
LoadStruct 加载从 f 到 dst 的字段。dst 必须是结构体指针。
Atom
type Atom string
Atom 是一个文档字段,其内容以单个不可分割的字符串的形式编入索引。
Cursor
type Cursor string
Cursor 表示迭代器的位置。
游标的字符串值在网络上是安全的。它可以保存起来,在恢复后可供日后使用。
DocumentMetadata
type DocumentMetadata struct {
// Rank is an integer specifying the order the document will be returned in
// search results. If zero, the rank will be set to the number of seconds since
// 2011-01-01 00:00:00 UTC when being Put into an index.
Rank int
// Facets is the set of facets for this document.
Facets []Facet
}
DocumentMetadata 是一个包含给定文档的描述信息的结构体。
ErrFacetMismatch
将构面加载到与其先前存储类型不同的类型时,或者在目标结构体中缺少或未导出字段时,系统将返回 ErrFacetMismatch。StructType 是传递给 Iterator.Next 的目标参数指向的结构体类型。
func (*ErrFacetMismatch) Error
func (e *ErrFacetMismatch) Error() string
ErrFieldMismatch
将字段加载到与其先前存储类型不同的类型时,或者在目标结构体中缺少或未导出字段时,系统将返回 ErrFieldMismatch。
func (*ErrFieldMismatch) Error
func (e *ErrFieldMismatch) Error() string
Facet
type Facet struct {
// Name is the facet name. A valid facet name matches /[A-Za-z][A-Za-z0-9_]*/.
// A facet name cannot be longer than 500 characters.
Name string
// Value is the facet value.
//
// When being used in documents (for example, in
// DocumentMetadata.Facets), the valid types are:
// - search.Atom,
// - float64.
//
// When being used in SearchOptions.Refinements or being returned
// in FacetResult, the valid types are:
// - search.Atom,
// - search.Range.
Value interface{}
}
Facet 是一个名称/值对,用于向文档添加分类信息。
FacetResult
type FacetResult struct {
Facet
// Count is the number of times this specific facet and value appeared in the
// matching documents.
Count int
}
FacetResult 表示在与搜索请求匹配的文档中,特定构面和值出现的次数。
FacetSearchOption
type FacetSearchOption interface {
// contains filtered or unexported methods
}
FacetSearchOption 控制搜索结果中返回的构面信息。
func AutoFacetDiscovery
func AutoFacetDiscovery(facetLimit, valueLimit int) FacetSearchOption
AutoFacetDiscovery 会返回 FacetSearchOption,用于为搜索启用自动构面发现。自动构面发现用于查找匹配文档汇总中最常出现的构面。
返回的最大构面数由 facetLimit 控制,每个构面的最大值也由 facetLimit 控制。限值为零表示应使用默认限值。
func FacetDiscovery
func FacetDiscovery(name string, value ...interface{}) FacetSearchOption
FacetDiscovery 会返回 FacetSearchOption,用于选择将与搜索结果一起返回的构面。默认情况下,系统将返回该构面最常出现的值。但是,您还可以指定要返回的特定 Atom 或特定 Range 的列表。
func FacetDocumentDepth
func FacetDocumentDepth(depth int) FacetSearchOption
FacetDocumentDepth 会返回 FacetSearchOption,用于通过正在准备的构面结果控制要计算的文档数。
Field
type Field struct {
// Name is the field name. A valid field name matches /[A-Za-z][A-Za-z0-9_]*/.
Name string
// Value is the field value. The valid types are:
// - string,
// - search.Atom,
// - search.HTML,
// - time.Time (stored with millisecond precision),
// - float64,
// - GeoPoint.
Value interface{}
// Language is a two-letter ISO 639-1 code for the field's language,
// defaulting to "en" if nothing is specified. It may only be specified for
// fields of type string and search.HTML.
Language string
// Derived marks fields that were calculated as a result of a
// FieldExpression provided to Search. This field is ignored when saving a
// document.
Derived bool
}
Field 是名称/值对。可以加载搜索索引的文档并将其另存为一系列 Field。
func SaveStruct
SaveStruct 会将 src 中的字段以 Field 切片形式返回。src 必须是结构体指针。
FieldExpression
type FieldExpression struct {
// Name is the name to use for the computed field.
Name string
// Expr is evaluated to provide a custom content snippet for each document.
// See https://cloud.google.com/appengine/docs/standard/go/search/options for
// the supported expression syntax.
Expr string
}
FieldExpression 定义要为每个结果求值的自定义表达式。
FieldList
type FieldList []Field
FieldList 会转换 []Field 以实现 FieldLoadSaver。
func (*FieldList) Load
func (l *FieldList) Load(f []Field, _ *DocumentMetadata) error
Load 会将所有提供的构面加载到 l 中,而不会先将 *l 重置为空切片。
func (*FieldList) Save
func (l *FieldList) Save() ([]Field, *DocumentMetadata, error)
Save 会将 l 的所有字段以 Field 切片的形式返回。
FieldLoadSaver
type FieldLoadSaver interface {
Load([]Field, *DocumentMetadata) error
Save() ([]Field, *DocumentMetadata, error)
}
FieldLoadSaver 可以与包含其他文档元数据的 Field 切片相互转换。
HTML
type HTML string
HTML 是一个文档字段,其内容以 HTML 的形式编入索引。仅文本节点编入索引:“foobar”将被视为“foobar”。
Index
type Index struct {
// contains filtered or unexported fields
}
Index 是文档的索引。
func Open
Open 会打开具有给定名称的索引。如果索引尚不存在,则创建索引。
名称是直观易懂的 ASCII 字符串。它不能包含空白字符,不能以“!”开头。
func (*Index) Delete
Delete 会从索引中删除文档。
func (*Index) DeleteMulti
DeleteMulti 会从索引中删除多个文档。
返回的错误可能是 appengine.MultiError 实例,在这种情况下,其大小与 src 相同,并且其中的每个错误都将与 src 中的项相对应。
func (*Index) Get
Get 会将具有给定 ID 的文档加载到 dst 中。
ID 是直观易懂的 ASCII 字符串。它必须为非空,不得包含空白字符,且不能以“!”开头。
dst 必须是非 nil 结构体指针或实现 FieldLoadSaver 接口。
将字段加载到与其先前存储类型不同的类型时,或者在目标结构体中缺少或未导出字段时,系统将返回 ErrFieldMismatch。只有在 dst 是结构体指针时,系统才会返回 ErrFieldMismatch。由被调用者决定此错误是严重错误、可恢复错误还是可忽略错误。
func (*Index) List
func (x *Index) List(c context.Context, opts *ListOptions) *Iterator
List 会列出索引中的所有文档。文档以递增的 ID 顺序返回。
func (*Index) Put
Put 会将 src 保存到索引中。如果 ID 为空,则服务会分配新 ID 并返回。如果 ID 不为空,则替换该 ID 的任何现有索引条目。
ID 是直观易懂的 ASCII 字符串。它不能包含空白字符,不能以“!”开头。
src 必须是非 nil 结构体指针或实现 FieldLoadSaver 接口。
func (*Index) PutMulti
PutMulti 与 Put 类似,但用于一次将多个文档添加到索引中时效率更高。
一次最多可以添加 200 个文档。如果您尝试添加更多文档,则会返回 ErrTooManyDocuments。
ID 可以是空切片(这意味着将为每个添加的文档分配新 ID),或者是与 src 大小相同的切片。
错误可能是 appengine.MultiError 实例,在这种情况下,其大小与 src 相同,并且其中的每个错误都将与 src 中的项相对应。
func (*Index) Search
Search 会搜索给定查询的索引。
Iterator
type Iterator struct {
// contains filtered or unexported fields
}
Iterator 是搜索查询索引或列出索引的结果。
func (*Iterator) Count
Count 会返回查询匹配的文档数的近似值。只有调用 Search 返回的迭代器才有效。
func (*Iterator) Cursor
Cursor 返回与当前文档关联的游标(即最近通过调用 Next 返回的文档)。
在将来调用 Search 时传递此游标将导致这些结果从当前文档之后的第一个文档开始。
func (*Iterator) Facets
func (t *Iterator) Facets() ([][]FacetResult, error)
如果在 SearchOptions 中请求了任何构面,Facets 将返回搜索结果中找到的构面。
func (*Iterator) Next
Next 会返回下一个结果的 ID。如果没有更多结果,Next 会将 Done 作为错误返回。
dst 必须是非 nil 结构体指针,实现 FieldLoadSaver 接口,或者是 nil 接口值。如果提供了非 nil 的 dst,则将填充已编入索引的字段。如果使用 IDsOnly 选项创建此迭代器,则忽略 dst。
ListOptions
type ListOptions struct {
// StartID is the inclusive lower bound for the ID of the returned
// documents. The zero value means all documents will be returned.
StartID string
// Limit is the maximum number of documents to return. The zero value
// indicates no limit.
Limit int
// IDsOnly indicates that only document IDs should be returned for the list
// operation; no document fields are populated.
IDsOnly bool
}
ListOptions 是用于列出索引中的文档的选项。传递 nil*ListOptions 等同于使用默认值。
Range
type Range struct {
Start, End float64
}
Range 表示包含开始值和不包含结束值的数值范围。 Start 可以指定为 math.Inf(-1),表示没有最小值,End 同样可以指定为 math.Inf(1);Start 或 End 这两者中至少有一个必须是有限大数值。
func AtLeast
AtLeast 会返回与任何大于或等于最小值的值匹配的 Range。
func LessThan
LessThan 会返回与任何小于最大值的值匹配的 Range。
Scorer
type Scorer interface {
// contains filtered or unexported methods
}
Scorer 定义文档的评分方式。
MatchScorer、RescoringMatchScorer
var (
// MatchScorer assigns a score based on term frequency in a document.
MatchScorer Scorer = enumScorer{pb.ScorerSpec_MATCH_SCORER}
// RescoringMatchScorer assigns a score based on the quality of the query
// match. It is similar to a MatchScorer but uses a more complex scoring
// algorithm based on match term frequency and other factors like field type.
// Please be aware that this algorithm is continually refined and can change
// over time without notice. This means that the ordering of search results
// that use this scorer can also change without notice.
RescoringMatchScorer Scorer = enumScorer{pb.ScorerSpec_RESCORING_MATCH_SCORER}
)
SearchOptions
type SearchOptions struct {
// Limit is the maximum number of documents to return. The zero value
// indicates no limit.
Limit int
// IDsOnly indicates that only document IDs should be returned for the search
// operation; no document fields are populated.
IDsOnly bool
// Sort controls the ordering of search results.
Sort *SortOptions
// Fields specifies which document fields to include in the results. If omitted,
// all document fields are returned. No more than 100 fields may be specified.
Fields []string
// Expressions specifies additional computed fields to add to each returned
// document.
Expressions []FieldExpression
// Facets controls what facet information is returned for these search results.
// If no options are specified, no facet results will be returned.
Facets []FacetSearchOption
// Refinements filters the returned documents by requiring them to contain facets
// with specific values. Refinements are applied in conjunction for facets with
// different names, and in disjunction otherwise.
Refinements []Facet
// Cursor causes the results to commence with the first document after
// the document associated with the cursor.
Cursor Cursor
// Offset specifies the number of documents to skip over before returning results.
// When specified, Cursor must be nil.
Offset int
// CountAccuracy specifies the maximum result count that can be expected to
// be accurate. If zero, the count accuracy defaults to 20.
CountAccuracy int
}
SearchOptions 是搜索索引的选项。传递 nil*SearchOptions 等同于使用默认值。
SortExpression
type SortExpression struct {
// Expr is evaluated to provide a sorting value for each document.
// See https://cloud.google.com/appengine/docs/standard/go/search/options for
// the supported expression syntax.
Expr string
// Reverse causes the documents to be sorted in ascending order.
Reverse bool
// The default value to use when no field is present or the expresion
// cannot be calculated for a document. For text sorts, Default must
// be of type string; for numeric sorts, float64.
Default interface{}
}
SortExpression 定义用于对文档进行排序的单个维度。
SortOptions
type SortOptions struct {
// Expressions is a slice of expressions representing a multi-dimensional
// sort.
Expressions []SortExpression
// Scorer, when specified, will cause the documents to be scored according to
// search term frequency.
Scorer Scorer
// Limit is the maximum number of objects to score and/or sort. Limit cannot
// be more than 10,000. The zero value indicates a default limit.
Limit int
}
SortOptions 控制搜索结果的排序和评分。