User Guide Getting Started Help Center Documentation Community Training
New LookML
Old LookML
New LookML
Looker
  
English
Français
Deutsch
日本語
Reusing Code with Extends

This is an advanced topic that assumes a solid knowledge of LookML.

As your LookML model expands in size and complexity, it becomes increasingly useful to reuse your LookML in multiple places. Looker has the option to extend Explores, views, and LookML dashboards so that you can do just that.

The extends parameter allows you to reuse code, which helps you to do the following:

Overview

When you extend a LookML object, you build on its contents with the contents of another LookML object. If there are any conflicts, the extending object will use its own settings, overriding the settings of the object being extended.

Here is an example of extending an Explore:

explore: customer { persist_for: "12 hours" }   explore: transaction { extends: [customer] persist_for: "5 minutes" }

In this example we have an Explore called Customer, and we created a second Explore called Transaction that extends it. Everything that is in Customer, such as its joins, will be included in Transaction. Anything that is in Transaction will remain in Transaction.

But notice there is a conflict: The Customer Explore says the persist_for setting should be 12 hours, but the Transaction Explore says it should be 5 minutes. For the Transaction Explore, the persist_for: "5 minutes" setting will be used, because it overwrites the setting from the Explore it’s extending.

The extends parameter works with views, Explores, and LookML dashboards. Follow these links for more information about each:

Models cannot be extended. However, in our model file we can include another model, which allows us to extend the Explores within it, as described in this Community topic. But we cannot extend a model file itself.

Extending a LookML Dashboard

To extend a LookML dashboard, both the extended and extending dashboards must be included in the model file. If a dashboard using the extends parameter is included in a model file without the base dashboard it extends, you’ll get a LookML validation error that the base dashboard can’t be found (among other errors).

Here’s an example dashboard file:

File: faa.dashboard.lookml

- dashboard: faa title: FAA Dashboard layout: newspaper elements: - title: Aircraft Location name: Aircraft Location model: e_faa explore: aircraft type: looker_map fields: - aircraft.zip - aircraft.count sorts: - aircraft.count desc limit: 500 query_timezone: America/Los_Angeles series_types: {} row: 0 col: 0 width: 8 height: 6

We can create a new LookML dashboard file and extend the FAA dashboard by adding a new tile:

File: faa_additional.dashboard.lookml

- dashboard: faa_additional title: FAA Additional extends: faa elements: - title: Elevation Count name: Elevation Count model: e_faa explore: airports type: looker_scatter fields: - airports.elevation - airports.count sorts: - airports.count desc limit: 500 query_timezone: America/Los_Angeles row: 0 col: 8 width: 8 height: 6

Because it extends the FAA dashboard, the FAA Additional dashboard will include any tiles that are defined in the faa.dashboard.lookml file. In addition, the FAA Additional dashboard will have any tiles that are defined in its own faa_additional.dashboard.lookml file.

The easiest way to create a LookML dashboard is to get the LookML from a user-defined dashboard. You can also use this technique to get the LookML for individual dashboard tiles. If you are using this method, be very sure that the positions of your tiles don’t overlap. In the example above, the tiles are both on the top row of the dashboard, which is indicated by row: 0:

File: faa.dashboard.lookml

row: 0 col: 0 width: 8 height: 6

However, the new tile we’re adding in the FAA Additional dashboard is in col: 8 so it’s displayed next to the tile from the extended dashboard:

File: faa_additional.dashboard.lookml

row: 0 col: 8 width: 8 height: 6

This is an easy thing to miss, since these elements are in different dashboard files. So if you’re adding tiles to an extended dashboard, be sure to check for positioning conflicts between tiles in the extended dashboard and tiles in the extending dashboard.

Requiring Extension

You can use the extension: required parameter to flag a LookML object as requiring extension, which means that the object cannot be used on its own. An object with extension: required is not visible to users on its own; it is intended only to act as a starting point to be extended by another LookML object. The extension parameter is supported for Explores, views, and LookML dashboards.

Details of Extend Functionality

It’s a good idea to know exactly how extends are executed so that you can understand the behavior, and so you can use them in complex ways. Looker takes these basic steps when extending a LookML object:

  1. A copy is made of the explicitly defined LookML objects inside the dashboard, view, or Explore that is being extended.
  2. The copies are merged with the explicitly defined LookML objects inside the dashboard, view, or Explore that is doing the extending.
  3. If a LookML object is explicitly defined in both places, the object from the extending dashboard, view, or Explore is used.
  4. The resulting LookML is interpreted as normal.

Let’s look at an example to understand each of these steps in more detail.

Here is the LookML for our base view, the User view:

view: user { suggestions: yes   dimension: name { sql: ${TABLE}.name ;; } }

And here is another view file, the User With Age Extensions view, which extends the User view:

view: users_with_age_extensions { extends: [user] suggestions: no   dimension: age { type: number sql: ${TABLE}.age ;; } }

Step 1: Copy

In this case the users view is being extended into the users_with_age_extensions view. Since users is the view that is being extended, a copy of it is made before merging. Understanding that a copy is made is not particularly important, other than to realize that the original users view is left unchanged, and usable as normal.

Step 2: Merge

The next step is for all of the LookML from the extended view (users) to be merged into the extending view (users_with_age_extensions). It’s important to understand the nature of this merge, which is simply a merging of YAML hashes (YAML is the language on which LookML is based). In practical terms this means that any explicitly written LookML gets merged, but the default LookML values that you haven’t written down don’t get merged. In a sense, it’s really just the text of the LookML that is getting put together, and none of the meaning of that text.

Step 3: Resolve Conflicts

The third step is resolving any conflicts between the merged views. The extending view is the view that will “win,” which in this case is users_with_age_extensions. The fact that default LookML values aren’t being considered yet is important, because you don’t want to make the mistake of thinking that conflicts between default values are getting resolved. In actuality, they’re just being ignored at this step. That is why we need to explicitly add additional parameters when extending objects:

In this particular example we have not added sql_table_name to the User view, which is going to cause some problems in the next step.

Step 4: Interpret the LookML

In the final step, the resulting LookML is interpreted as normal, including all the default values. In this particular example we’ve ended up with LookML that includes view: users_with_age_extensions, but no sql_table_name parameter. As a result, Looker is going to assume that the value of sql_table_name is equal to the view name:

The problem is that there is probably no table in our database called users_with_age_extensions. This is why we need to add a sql_table_name parameter to any view that is going to be extended. Adding view_name and view_label to Explores that will be extended avoids similar problems.

Advanced Usage

Extending More Than One Object at the Same Time

It is possible to extend more than one dashboard, view, or Explore at the same time. For example:

explore: orders { extends: [user_info, marketing_info] } # Also works for dashboards and views

The extension process works exactly as described above, but you’ll need to keep one extra rule in mind about how conflicts are resolved. If there are any conflicts between the multiple items listed in the extends parameter, priority is given to the items listed last. So in the example above, if there were conflicts between user_info and marketing_info, the marketing_info Explore would win.

Chaining Together Multiple Extends

You can also chain together as many extends as you’d like. For example:

explore: orders { extends: [user_info] … } explore: user_info { extends: [marketing_info] … }

Again, the extension process works exactly as described above, with one extra rule about conflict resolution. If there are any conflicts, priority is given to the last item in the chain of extends. In this example:

Additional Options with Lists

When working with lists you may choose to combine them, instead of having the extending object’s list be the winner. Consider this simple extension with a conflicting list called animals:

view: pets { extends: fish set: animals { fields: [dog, cat] } } view: fish { set: animals { fields: [goldfish, guppy] } }

In this case the pets view is doing the extending, and will therefore win, making animals contain [dog, cat]. However, by making use of the special EXTENDED* set, you can combine the lists instead:

view: pets { extends: fish set: animals { fields: [dog, cat, EXTENDED*] } } view: fish { set: animals { fields: [goldfish, guppy] } }

Now the animals list will contain [dog, cat, goldfish, guppy].

Combining Instead of Replacing During Conflict Resolution

In the basic behavior described above we mentioned that, if there are any conflicts during extension, the extending object wins. For example, take this simple extension:

view: product_short_descriptions { extends: products dimension: description { sql: ${TABLE}.short_description ;; } } view: products { dimension: description { sql: ${TABLE}.full_description ;; } }

You can see there is a conflict of the sql parameter within the description dimension. Typically, the definition from product_short_descriptions will simply overwrite the definition from products because it is doing the extending.

However, you can also choose to combine the definitions if you like. To do so, you’ll use the ${EXTENDED} keyword like this:

view: product_short_descriptions { extends: products dimension: description { sql: LEFT(${EXTENDED}, 50) ;; } } view: products { dimension: description { sql: ${TABLE}.full_description ;; } }

Now the conflict of the sql parameter will be addressed differently. Instead of the product_short_descriptions definition winning, it will take the definition from products and insert it where ${EXTENDED} is used. The resulting definition for description in this case will be: LEFT(${TABLE}.full_description, 50).

Top