doc.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Copyright 2015 Google Inc. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. /*
  5. Package search provides a client for App Engine's search service.
  6. Basic Operations
  7. Indexes contain documents. Each index is identified by its name: a
  8. human-readable ASCII string.
  9. Within an index, documents are associated with an ID, which is also
  10. a human-readable ASCII string. A document's contents are a mapping from
  11. case-sensitive field names to values. Valid types for field values are:
  12. - string,
  13. - search.Atom,
  14. - search.HTML,
  15. - time.Time (stored with millisecond precision),
  16. - float64 (value between -2,147,483,647 and 2,147,483,647 inclusive),
  17. - appengine.GeoPoint.
  18. The Get and Put methods on an Index load and save a document.
  19. A document's contents are typically represented by a struct pointer.
  20. Example code:
  21. type Doc struct {
  22. Author string
  23. Comment string
  24. Creation time.Time
  25. }
  26. index, err := search.Open("comments")
  27. if err != nil {
  28. return err
  29. }
  30. newID, err := index.Put(ctx, "", &Doc{
  31. Author: "gopher",
  32. Comment: "the truth of the matter",
  33. Creation: time.Now(),
  34. })
  35. if err != nil {
  36. return err
  37. }
  38. A single document can be retrieved by its ID. Pass a destination struct
  39. to Get to hold the resulting document.
  40. var doc Doc
  41. err := index.Get(ctx, id, &doc)
  42. if err != nil {
  43. return err
  44. }
  45. Search and Listing Documents
  46. Indexes have two methods for retrieving multiple documents at once: Search and
  47. List.
  48. Searching an index for a query will result in an iterator. As with an iterator
  49. from package datastore, pass a destination struct to Next to decode the next
  50. result. Next will return Done when the iterator is exhausted.
  51. for t := index.Search(ctx, "Comment:truth", nil); ; {
  52. var doc Doc
  53. id, err := t.Next(&doc)
  54. if err == search.Done {
  55. break
  56. }
  57. if err != nil {
  58. return err
  59. }
  60. fmt.Fprintf(w, "%s -> %#v\n", id, doc)
  61. }
  62. Search takes a string query to determine which documents to return. The query
  63. can be simple, such as a single word to match, or complex. The query
  64. language is described at
  65. https://cloud.google.com/appengine/docs/go/search/query_strings
  66. Search also takes an optional SearchOptions struct which gives much more
  67. control over how results are calculated and returned.
  68. Call List to iterate over all documents in an index.
  69. for t := index.List(ctx, nil); ; {
  70. var doc Doc
  71. id, err := t.Next(&doc)
  72. if err == search.Done {
  73. break
  74. }
  75. if err != nil {
  76. return err
  77. }
  78. fmt.Fprintf(w, "%s -> %#v\n", id, doc)
  79. }
  80. Fields and Facets
  81. A document's contents can be represented by a variety of types. These are
  82. typically struct pointers, but they can also be represented by any type
  83. implementing the FieldLoadSaver interface. The FieldLoadSaver allows metadata
  84. to be set for the document with the DocumentMetadata type. Struct pointers are
  85. more strongly typed and are easier to use; FieldLoadSavers are more flexible.
  86. A document's contents can be expressed in two ways: fields and facets.
  87. Fields are the most common way of providing content for documents. Fields can
  88. store data in multiple types and can be matched in searches using query
  89. strings.
  90. Facets provide a way to attach categorical information to a document. The only
  91. valid types for facets are search.Atom and float64. Facets allow search
  92. results to contain summaries of the categories matched in a search, and to
  93. restrict searches to only match against specific categories.
  94. By default, for struct pointers, all of the struct fields are used as document
  95. fields, and the field name used is the same as on the struct (and hence must
  96. start with an upper case letter). Struct fields may have a
  97. `search:"name,options"` tag. The name must start with a letter and be
  98. composed only of word characters. If options is "facet" then the struct
  99. field will be used as a document facet. If options is "" then the comma
  100. may be omitted. There are no other recognized options.
  101. Example code:
  102. // A and B are renamed to a and b.
  103. // A, C and I are facets.
  104. // D's tag is equivalent to having no tag at all (E).
  105. // I has tag information for both the search and json packages.
  106. type TaggedStruct struct {
  107. A float64 `search:"a,facet"`
  108. B float64 `search:"b"`
  109. C float64 `search:",facet"`
  110. D float64 `search:""`
  111. E float64
  112. I float64 `search:",facet" json:"i"`
  113. }
  114. The FieldLoadSaver Interface
  115. A document's contents can also be represented by any type that implements the
  116. FieldLoadSaver interface. This type may be a struct pointer, but it
  117. does not have to be. The search package will call Load when loading the
  118. document's contents, and Save when saving them. In addition to a slice of
  119. Fields, the Load and Save methods also use the DocumentMetadata type to
  120. provide additional information about a document (such as its Rank, or set of
  121. Facets). Possible uses for this interface include deriving non-stored fields,
  122. verifying fields or setting specific languages for string and HTML fields.
  123. Example code:
  124. type CustomFieldsExample struct {
  125. // Item's title and which language it is in.
  126. Title string
  127. Lang string
  128. // Mass, in grams.
  129. Mass int
  130. }
  131. func (x *CustomFieldsExample) Load(fields []search.Field, meta *search.DocumentMetadata) error {
  132. // Load the title field, failing if any other field is found.
  133. for _, f := range fields {
  134. if f.Name != "title" {
  135. return fmt.Errorf("unknown field %q", f.Name)
  136. }
  137. s, ok := f.Value.(string)
  138. if !ok {
  139. return fmt.Errorf("unsupported type %T for field %q", f.Value, f.Name)
  140. }
  141. x.Title = s
  142. x.Lang = f.Language
  143. }
  144. // Load the mass facet, failing if any other facet is found.
  145. for _, f := range meta.Facets {
  146. if f.Name != "mass" {
  147. return fmt.Errorf("unknown facet %q", f.Name)
  148. }
  149. m, ok := f.Value.(float64)
  150. if !ok {
  151. return fmt.Errorf("unsupported type %T for facet %q", f.Value, f.Name)
  152. }
  153. x.Mass = int(m)
  154. }
  155. return nil
  156. }
  157. func (x *CustomFieldsExample) Save() ([]search.Field, *search.DocumentMetadata, error) {
  158. fields := []search.Field{
  159. {Name: "title", Value: x.Title, Language: x.Lang},
  160. }
  161. meta := &search.DocumentMetadata{
  162. Facets: {
  163. {Name: "mass", Value: float64(x.Mass)},
  164. },
  165. }
  166. return fields, meta, nil
  167. }
  168. */
  169. package search