[ Update: the Freebase type provider is now available as part of the FSharp.Data NuGet package and library. The namespace has changed from "Samples.DataStore.Freebase" to "FSharp.Data". Find out more about F# at fsharp.org.  ]

The F# 3.0 Freebase Type Provider Sample includes some support for query translation from F# 3.0 LINQ queries to MQL. Some sample queries are here. You can write queries in F# 3.0 with auto-completion and strong typing, and still execute efficiently on the server, at least for those queries translated by the sample. Here are some details query translation in the sample at the time of writing.

  • Single, non-nested 'for' loops over a collection,

    for book in data.``Arts and Entertainment``.Books.Books do

  • Where clauses with a fairly simple range of constraints, e.g.

    where (e.``Atomic number``.Value = 20) // equality on primitive values

    where (isotope.``Isotope of``.``Atomic number``.Value = 20) // equality on nested value

    where (e.``Atomic number``.Value < 20) // ordering relations on primitive values

    where e.``Atomic number``.HasValue // non-emptiness of primitive values

    where (x.Damages <> null) // non-emptiness of compound collections

    where (elem.Symbol = "Na") // string equality

  • Approximate string matching, see the MQL cookbook operator "~="

    where (book.Name.ApproximatelyMatches "1984")

  • Selecting things  at the end of a query (if the items may contain unrealized compund objects, then those items will be populated on-demand)

    select (e.Name, e.``Boiling Point``)

  • Sorting on properties

    sortBy e.Name

    sortBy e.``Boiling Point``.Value

    sortByNullable e.``Boiling Point``

  • Exact counting, and Freebase approximate counting

    query { ... count }, or

    // Exact count of number of countries, some are historical  
    data.``Time and Space``.Location.Countries.Count()

    // Approximate count of number of books. There are around three million books
    // to search. Counting them exactly takes too long on the server

    data.``Arts and Entertainment``.Books.Books.ApproximateCount()

At the time of writing there are some limitations

  • Date values are not handled very well - they are translated as strings, but you can't, for example, compare by date
  • When you select compound objects in a query, the object will use "delayed loading". This may lead to later implicit server requests when you access properties on those objects. These may "cascade".
  • There are many, many things which can't be represented in queries. In general, try to stick to a known, working query format, or use client side processing for anything beyond samples which you know work

By default, the portion of queries that can't be executed on the server gets executed on the client side. You can adjust that behaviour to throw an exception instead by setting AllowLocalQueryEvaluation to false. Executing on the client side can give a much nicer programming experience for data scripting against  small data sets (or prefixes of large data sets), but obviously for much larger data sets such as "books" or "films" this is not appropriate.In data scripting a bit of local query evaluation may not matter (you can always interrupt execution), but in finished applications you will want to avoid it.

Note, it is helpful to add the following to see how many requests are being sent to the server:

    data.DataContext.SendingRequest.Add (fun e -> printfn "request: %A" e.RequestUri)