Oturum açın

Creating an Advanced Subscribed Link

The previous pages explored how you can compose queries and responses, use variables, and define data objects. They also discussed how you can create fairly large sets of queries and responses more efficiently. This page goes further and demonstrates a few more techniques for streamlining your development, filtering out data objects, and calculating values.

Contents

This page includes the following sections:

Looking Up Data in Multiple Steps

After you create a good number of data objects, you might find yourself replicating a lot of the same information across multiple data objects. Let's say, you are creating a subscribed link for badminton players. You decided that the custom results would display a bit of information about the players and their coaches. So you start creating a data object for each player. The data object would have a query pattern for the player's name to account for the various ways that people might search for the player, and it would also have attribute values that contain some data about the player and his or her coach. Great. Then you move on to the next player, who also trains under the same coach. You create some player-specific data and repeat the exact information about the coach. After creating a few more data objects for players who train under the same coach, you get tired of repeating the same chunk of information across multiple data objects. This is where extractors come in handy.

Extractors are variables or placeholders that let your ResultSpec element look up data in multiple steps. You can layer one extractor on top of another, with each extractor passing the attribute values from the previous extracted objects to the next ones. You can save a lot of time if you take repeated attribute values and house them in another data object, then use extractors to look up the repeated attribute values. In the badminton player example, we would be creating a set of data objects for all the players and another set of data objects for their coaches. The Subscribed Links API pulls data from a player data object and a coach data object and plugs the values in the custom result.

To create extractors that look up another data object.

  1. Add the Extract element right after the Query element.
  2. Define the extractor type. Use the type of the data object from which you want to extract data. The type is the value of the DataObject type attribute.
  3. Specify the attribute variable whose value the extractor should hold and use to look up the next data object. The extractor, like all other variables, should be enclosed in brackets ([]).

Attribute variables in the Response element can refer to objects in the extractors, just as they can refer to object types in the query. So when you increment the object identifier, include both extractors and object types in the count. For example, if you have a Query element with two object types, [person] and [city], and an extractor, then attribute variables that refer to [person] would have an object identifier of 0; attribute variables that refer to [city], 1; attribute variables that refer to the extractor, 2.

Extractor Example: Code

The following code, which uses fictitious names, demonstrates how you can create an extractor for a subscribed link on badminton players :

<Results>

<AuthorInfo description="Profile of Active Badminton Players" author="Badminton Fan"/>

<ResultSpec id="ActiveBadmintonPlayers">

    <Query>[Player]</Query>
    <Extract type="Coach">[0.coach_name]</Extract>

	<Response format="image">
    <Output name="title">[0.player_name] plays for the [0.team_name]</Output>
    <Output name="more_url">http://www.google.com/some_url/example/[0.player_name]</Output>
    <Output name="text1">[0.player_name] is currently ranked number [0.seed]</Output>
    <Output name="text2">and trains under [0.coach_name], who last competed for [1.team_name] in the [1.event]</Output>
	</Response>    

</ResultSpec>

<!--Data object for the players-->
<DataObject type="Player" id="AvelinoGubat">

    <QueryName value="Avelino"/>
    <QueryName value="Avelino Gubat"/>
    <QueryName value="The Hammer"/>

    <Attribute name="player_name" value="Avelino Gubat"/>
    <Attribute name="team_name" value="Philippine National Team"/>
    <Attribute name="seed" value="102"/>
    <Attribute name="coach_name" value="Lim Tiong-Chun"/>

</DataObject>

<DataObject type="Player" id="TaufikGade">

    <QueryName value="Gade"/>
    <QueryName value="Taufik Gade"/>

    <Attribute name="player_name" value="Taufik Gade"/>
    <Attribute name="team_name" value="Malaysia National Team"/>
    <Attribute name="seed" value="1"/>
    <Attribute name="coach_name" value="Lim Tiong-Chun"/>

</DataObject>

<!--Data object for the coach.-->
<DataObject type="Coach" id="LimTiongChun">

    <QueryName value="Lim Tiong-Chun"/>

    <Attribute name="team_name" value="Malaysia National Team"/>
    <Attribute name="event" value="1984 Thomas Cup"/>
    <Attribute name="losses" value="0"/>
    <Attribute name="rank" value="1st"/>
    
</DataObject>

</Results>

Extractor Example: Preview

The sample code displays the following result on the query "avelino gubat":

Custom result created with an extractor

Walking Through the Sample Code

To get a better understanding of how extractors interact with the query, response, and data object, let's walk through the sample code section by section.

The Query

If the typed search query matches the value of the Query element and the value in the object type matches one of the QueryName elements in a data object, the Subscribed Links API grabs the values in the Attribute elements of the matched data object and plugs them into the attribute variables in the response.

Consider the Query snippet of our sample code:

    <Query>[Player]</Query>

When the subscriber types the name of the badminton player, the Subscribed Links API goes through the data objects until it finds a match. So when the subscriber types: "Avelino Gubat" or any of the values in the QueryName section of the AvelinoGubat data object, a response is triggered.

To learn more about queries, see the Creating Patterns of Queries page.

The Extractor

An extractor is like a secondary object type. Instead of holding the value of the user's search term, the extractor holds the value of a specific attribute variable.

Consider the Extract snippet of our sample code:

<Extract type="Coach">[0.coach_name]</Extract>

In this case, the extractor is holding "Lim Tiong-Chun", which is the value of attribute variable (coach_name) of the object. The object identifier 0 tells us that it is referring to the first object, which is [Player] in the Query element.

Variables that refer to the extracted object use the object identifier 1, because the extractor is the second object after the object type.

The Response

The response includes attribute variables and extractor variables. The Subscribed Links API replaces these variables with the values defined in the matched data objects.

Consider the Response snippet of our sample code:

<Response>

    <Output name="title">[0.player_name]plays for the [0.team_name]</Output>
    <Output name="more_url">http://www.google.com/some_url/example/[0.player_name]</Output>
    <Output name="text1">[0.player_name] is currently ranked number [0.seed]./Output>
    <Output name="text2">and trains under [0.coach_name], who last competed for [1.team_name] in the [1.event]</Output>

</Response>    

<!--The following data object matches the value of the object type. 
The attribute values are plugged into variables with the object identifier of 0--> <DataObject type="Player" id="AvelinoGubat"> <QueryName value="Avelino"/> <QueryName value="Avelino Gubat"/> <QueryName value="The Hammer"/> <Attribute name="image_src" value="http://www.google.com/some_url/example/limtiongchun.jpg"/> <Attribute name="player_name" value="Avelino Gubat"/> <Attribute name="team_name" value="Philippine National Team"/> <Attribute name="seed" value="102"/> <Attribute name="coach_name" value="Lim Tiong-Chun"/> </DataObject> <!--The following data object matches the value of the extractor.
The attribute values are plugged into variables with the object identifier of 1--> <DataObject type="Coach" id="LimTiongChun"> <QueryName value="Lim Tiong-Chun"/> <Attribute name="team_name" value="Malaysia National Team"/> <Attribute name="event" value="1984 Thomas Cup"/> </DataObject>

Because the search for "Avelino Gubat" matches a data object, the API replaces the attribute variables in the response with the values defined in the data object. So the API replaces the attribute variables, 0.team_name, 0.player_name, and 0.seed with the values "Philippine National Team", "Avelino Gubat", and "102", respectively.

The variables that are preceded with the object identifier 1 refer to the attributes of the second object, which is in <Extract type="Coach">[0.coach_name]</Extract>. The API matches the extracted value, "Lim Tiong-Chun" to the data object with <QueryName value="Lim Tiong-Chun"/>. The API then replaces the attribute variables in the response with values defined in the LimTiongChun data object. So the API replaces the attribute variables, 1.team_name and 1.event with the values "Malaysia National Team" and "1984 Thomas Cup", respectively.

To learn more about forming responses, see the Creating a Subscribed Link Using XML page; to learn more about creating and using attribute variables, see Creating Response Templates; to learn more about changing the look and feel of your custom result or including images (such as pictures of badminton players), see Designing the Look and Feel.

Calculating Values

If you want to create subscribed link that can compute values, use extractors and the standard Google operators. The Subscribed Links API matches any input string that it recognizes as a valid numerical expression and calls the Google calculator to compute the result. You can pass one calculated value from one extractor to another until the final value is calculated.

To create a calculator:

  1. Add the Extract element right after the Query element.
  2. Set the Extract type to calculate.
      <Extract type="calculate"> </Extract>  
  3. Specify the values that you want to be calculated.

    Each extracted object must have an object identifier and the object identifier must increment by one for each progressive extracted object. If the first extracted object is [0.number], the next extracted objects should be [1.number], [2.number], and so on.

    The calculate extractor provides you with pre-defined objects, which includes the following:
    • number - stores the raw number. This object is best for calculating arithmetic.
    • units - stores the number and the unit. This object is best for unit conversions. It takes the input string (such as "3 km in miles") and stores the converted number and the unit (such as "1.86411358 miles"). If the input string does not include a unit (such as "2 * 3"), the object will hold an empty string.
    • result_str - stores a pretty-printed version of the calculation. For example, if the input string is "2 km + 3 feet in miles", the object stores "1.24331057 miles".
    • expr - stores the parenthesized version of the input string. The parentheses clarify the order of operations. For example, if the input string is "2 km * 2 + 3 feet in miles", the object stores " ((2 km) * 2) + (3 feet)".

Calculator Example: Code

The following example demonstrates how you can calculate the distance between two airports using the great-circle distance formula. The formula lets you calculates the shortest distance between two points (whose latitude and longitude are known) on a surface of a spherical object.

The example has a Query element with two object types and seven extractors, each of which holds a calculated value. The first [GeoPoint] is object 0 and the second [GeoPoint] is object 1. The seven extractors are objects 2 through 8.

<Results>

<AuthorInfo description="Calculator for distance between airports" author="Jane Author"/>

<ResultSpec id="GreatCircleDistance">

  <Query>distance from [GeoPoint] to [GeoPoint]</Query>
  <Extract type="calculate">[0.lat] * Pi / 180</Extract>
  <Extract type="calculate">[1.lat] * Pi / 180</Extract>
  <Extract type="calculate">([0.lng] - [1.lng]) * Pi / 180</Extract>
  <Extract type="calculate">(cos [3.number] * sin [4.number])^2 + (cos [2.number] sin [3.number] - sin [2.number] cos [3.number] cos [4.number])^2</Extract>
  <Extract type="calculate">sin [2.number] sin [3.number] + cos [2.number] cos [3.number] cos [4.number]</Extract>
  <Extract type="calculate">arctan (sqrt([5.number]) / [6.number]) * 6372.795</Extract>
  <Extract type="calculate">[7.number] km in miles</Extract>

  <Response>
    <Output name="title">Distance: [7.number] km</Output>
    <Output name="more_url">www.google.com</Output>
    <Output name="text1">The distance from [0.fullname] to [1.fullname]</Output>
    <Output name="text2">is [7.number] kilometers or [8.result_str].</Output>
  </Response>

</ResultSpec>

<DataObject id="BNA" type="GeoPoint">

  <QueryName value="BNA"/>

  <Attribute name="fullname" value="BNA airport"/>
  <Attribute name="lat" value="36.12"/>
  <Attribute name="lng" value="-86.67"/>

</DataObject>

<DataObject id="LAX" type="GeoPoint">

  <QueryName value="LAX"/>

  <Attribute name="fullname" value="LAX airport"/>
  <Attribute name="lat" value="33.94"/>
  <Attribute name="lng" value="-118.40"/>

</DataObject>

</Results>    

Calculator Example: Preview

The sample code displays the following result on the query "distance from LAX to BNA":

Referring to Attributes of Other Data Objects

If you want to insert attribute data from one data object to another without using extractors, you can use reference attributes. A reference attribute is different from extractors in that:

  • You can embed reference attributes directly in the the Response element without creating another XML element (such as an Extract element)
  • Reference attributes use the attribute names of the source data object and the referred data object (0.location.population), while extractor attributes just use attribute names of the referred data object (1.population)
  • Reference attributes look up data objects by the DataObject id, while an extractor looks up data objects by the QueryName.

While custom results that use reference attributes are easier to construct than ones that use extractors, they are not as powerful. You cannot look up data objects on multiple levels, and you have to know the ID of the data object.

A reference attribute includes the following components:

  • The object identifier. The identifier specifies the object with which the reference attribute is associated.
  • The attribute name of the source data object. The source data object has an attribute value that contains the DataObject id of the referred object.
  • The attribute name of the referred object. The referred data object contains attribute values that Google inserts into the attribute variable.

Separate each components of the reference attribute with a period (.) and enclose the attribute name in brackets ([ ]) .

Reference Attribute Example: Code

The following example demonstrates how you can use reference attributes.

<Results>
<AuthorInfo description="Profile of Badminton Players-Reference Attributes" Author="Badminton Fan"/> <ResultSpec id="ActiveBadmintonPlayer-ReferenceAttribute"> <Query>[Player]</Query> <Response> <Output name="title">[0.player_name] plays for the [0.team_name]</Output> <Output name="more_url">www.google.com/example/[0.player_name]</Output> <Output name="text1">[0.player_name] is currently ranked number [0.seed]</Output>
<Output name="text2">and is coached by [0.coach_id.coach_name], who last competed for the [0.coach_id.team_name] in the [0.coach_id.event].</Output>
</Response> </ResultSpec> <!--Source data object--> <DataObject id="AvelinoGubat" type="Player"> <QueryName value="Avelino Gubat"/>
<QueryName value="Avelino"/>
<QueryName value="Gubat"/>
<QueryName value="The Hammer"/> <Attribute name="player_name" value="Avelino Gubat"/>
<Attribute name="team_name" value="Philippine National Team"/>
<Attribute name="seed" value="102"/>
<Attribute name="coach_id" value="LimTiongChun"/> </DataObject> <!--Referred data object--> <DataObject id="LimTiongChun" type="Coach"> <QueryName value="Lim Tiong Chun"/> <Attribute name="coach_name" value="Lim Tiong Chun"/> <Attribute name="team_name" value="Malaysia National Team"/> <Attribute name="event" value="1984 Thomas Cup"/> </DataObject> </Results>

The sample code has three reference attributes: [0.coach_id.coach_name], [0.coach_id.team_name], and [0.coach_id.event]. The Subscribed Links API does the following sequence of events when a user searches for "avelino gubat":

  1. It evaluates the coach_id attribute value of object 0.
  2. It looks for a data object with an id value of "LimTiongChun".
  3. It gets the coach_name, team_name, and event attribute values of the LimTiongChun data object.
  4. It inserts the values in the reference attributes.

Reference Attribute Example: Preview

A search for "avelino gubat" would trigger the following custom result:

Custom result created with a reference attribute

Restricting Triggers

In some cases, you might want to restrict queries from triggering a response unless the query matches a specific condition. Let's say, you are creating a subscribed link for museums and you want Google to display custom results only if the query includes the museum and the right city; that is, Google displays custom results on search queries such as "Louvre in Paris" but not on "Louvre in Dallas".

Or, perhaps, you are using other people's data objects, and you want to use only a subset of their data objects. Let's say you are creating a subscribed link for restaurants in Minneapolis and you are using third-party data objects that covers national restaurants. You can use validators to filter out data objects about restaurants outside of Minneapolis and have Google display custom results only on search queries regarding restaurants in Minneapolis.

In both cases, validators would solve your problem. They restrict your result specification (the ResultSpec element) to display only a subset of data objects of a given type. A validator evaluates the values of attribute variables from two data objects and lets Google display a custom result only if both values are equal. By letting you limit what is displayed to your users, validators give you the following abilities:

  • Fine-tune the conditions under which a result specification is triggered.
  • Control third-party data objects, thus saving you from the hassle of having to retype other people's data objects just to make them fit your hierarchy of result specifications.

As with extractors, you add validators right after the Query element. A validator has the following components:

 <Validate src="[0.attributename]" dst="[1.attributename]"/>
  • The Validate tag
  • The source (src)
  • The destination (dst)

The validator compares the values between the source and destination, which are populated using attribute values of two data objects. Google displays a response only when the values between the source and the destination are equal.

Validator Example: Code

The following example demonstrates how you can use a validator to restrict the triggering. The subscribed link for museums display custom results only when the subscriber types the museum name and the correct city.

<Results>

<AuthorInfo description="Cultural Sites of the World" author="Jane Author"/>
 
<ResultSpec id="Museums">

  <Query>[Museum] in [WorldCity]</Query>
  <Validate src="[0.city]" dst="[1.fullname]"/>

  <Response>

    <Output name="title">[0.fullname] in [1.fullname]</Output>
    <Output name="more_url">www.google.com/example</Output>
    <Output name="text1">The [0.fullname] specializes in [0.collection].</Output>
    <Output name="text2">It is open [0.open].</Output>

  </Response>

</ResultSpec>

<!--Data objects for the museums. The validator uses these as the source--> 

<DataObject id="NationalPalaceMuseum" type="Museum">

  <QueryName value="National Palace Museum"/>

  <Attribute name="fullname" value="National Palace Museum"/>
  <Attribute name="collection" value="artifacts and artworks of China"/>
  <Attribute name="open" value="daily"/>
  <Attribute name="city" value="Taipei"/>

</DataObject>

<DataObject id="PalaceMuseum" type="Museum">

  <QueryName value="Palace Museum"/>

  <Attribute name="fullname" value="Palace Museum"/>
  <Attribute name="collection" value="artifacts and artworks of China"/>
  <Attribute name="open" value="Tuesday through Saturday, except on public holidays"/>
  <Attribute name="city" value="Beijing"/>

</DataObject>


<!--Data objects for the location. The validator uses these data objects as the destination.--> 

<DataObject id="Taipei" type="WorldCity">

  <QueryName value="Taipei"/>
  <Attribute name="fullname" value="Taipei"/>

</DataObject>

<DataObject id="Beijing" type="WorldCity">

  <QueryName value="Beijing"/>
  <Attribute name="fullname" value="Beijing"/>

</DataObject>


</Results>

The sample code has a validator with a source value of [0.city] and a destination value of [1.fullname]. When a user searches for "palace museum in beijing", the Subscribed Links API evaluates the city attribute value of object 0, which pertains to data objects of the type Museum, and the fullname attribute value of object 1, which pertains to data objects of the type WorldCity. And because the attribute values of [0.city] (which is <Attribute name="city" value="Beijing"/> ), and [1.fullname](<Attribute name="fullname" value="Beijing"/>) are the same, Google displays the response defined in the results specification.

But if the user erroneously types "palace museum in taipei", Google does not display a custom result.

Validator Example: Preview

A search for "palace museum in beijing" would trigger the following custom result:

Custom result created with validators

Selecting Result Specifications Based on Query Conditions

If you want your subscribed link to use a particular result specification for one form of query and another result specification for another form of query, you can use validators or, alternatively, you can add different object types.

Let's expound on the previous Museum example. You might anticipate your users' confusion about the similar eminent Chinese museums, the National Palace Museum in Taipei and the Palace Museum in Beijing. So, to the previous museum XML example, you can add an anticipatory result specification for people who intend to learn more about the Palace Museum in the Forbidden City of Beijing, but erroneously typed "National Palace Museum in Beijing" instead of "Palace Museum in Beijing"

<!--Alternative result specification--> 

<ResultSpec id="Alternate_PalaceMuseum">

  <Query>[Museum] in [WorldCity]</Query>
  <Validate src="[0.other_city]" dst="[1.fullname]"/>

  <Response>

    <Output name="title">[0.fullname] in [0.city]</Output>
    <Output name="more_url">www.google.com/example</Output>
    <Output name="text1">The [0.fullname]is commonly confused with [0.alternative],</Output>
    <Output name="text2">which is located in [0.other city], not [0.city].</Output>

  </Response>

</ResultSpec>

Additionally, you would modify the data object to support the new result specification.

<DataObject id="NationalPalaceMuseum" type="Museum">

  <QueryName value="National Palace Museum"/>

  <Attribute name="fullname" value="National Palace Museum"/>
  <Attribute name="collection" value="artifacts and artworks of China"/>
  <Attribute name="open" value="daily"/>
  <Attribute name="city" value="Taipei"/>
  <Attribute name="other_city" value="the Forbidden City of Beijing"/>
  <Attribute name="alternative" value="Palace Museum"/>

</DataObject>

If you want to create a catch-all result specification that triggers a response based on a broader swath of queries, create a different object type for the broad trigger. Again, let's expound on the National Palace Museum example. We want the result specifications to have the following structure:

  • If [WorldCity]equals Taipei, then use <ResultSpec id="Museums">.
  • If [WorldCity]equals Beijing, then use <ResultSpec id="Alternate_PalaceMuseum">.
  • If [WorldCity]equals any other city besides Taipei and Beijing, then use <ResultSpec id="CatchAll_PalaceMuseum">.

The solution involves creating two alternative paths constructed with validators and a third catch-all path constructed with another object type and its associated data objects. So the third condition in the bulleted list would have an object type called something like [Other_WorldCity] instead of [WorldCity], and its data objects would include all the cities you want to cover.

As we discussed in the Following Best Practices section, avoid creating broad triggers that are not meaningful to your users. If your subscribed link keeps on displaying custom results that are tenuously related to the queries, you will annoy your users, who would remove you from their search results.

The Next Step

If you want to tweak the formatting of your custom results or go full blast with rich interface and configurability, read the Designing the Look and Feel page. The page shows you how you can change the text alignment, add images, or incorporate gadgets in your custom results. However, if you don't care for fancy presentations, you can start testing your subscribed link. Extractors and validators can get complicated, so you might discover a few kinks you need to fix.

 

< Back to Managing Multiple Data Objects | Forward to Designing the Look and Feel >