2016-05-13 49 views
8

Ayarlearndatalogtoday.org çalınan verilerle filmler ve döküm aşağıdaki DataScript veri tabanını düşünün: Aşağıdaki kod sürece project.clj bir bağımlılık [datascript "0.15.0"] içerdiği, JVM/Clojure Çoğaltma veya ClojureScript Çoğaltma çalıştırılabilir.DataScript'te tam olarak bir refs vektörü ile eşleşen bir sorgu nasıl oluşturulur?

  • filmi varlık:

    (ns user 
        (:require [datascript.core :as d])) 
    
    (def data 
        [["First Blood" ["Sylvester Stallone" "Brian Dennehy" "Richard Crenna"]] 
        ["Terminator 2: Judgment Day" ["Linda Hamilton" "Arnold Schwarzenegger" "Edward Furlong" "Robert Patrick"]] 
        ["The Terminator" ["Arnold Schwarzenegger" "Linda Hamilton" "Michael Biehn"]] 
        ["Rambo III" ["Richard Crenna" "Sylvester Stallone" "Marc de Jonge"]] 
        ["Predator 2" ["Gary Busey" "Danny Glover" "Ruben Blades"]] 
        ["Lethal Weapon" ["Gary Busey" "Mel Gibson" "Danny Glover"]] 
        ["Lethal Weapon 2" ["Mel Gibson" "Joe Pesci" "Danny Glover"]] 
        ["Lethal Weapon 3" ["Joe Pesci" "Danny Glover" "Mel Gibson"]] 
        ["Alien" ["Tom Skerritt" "Veronica Cartwright" "Sigourney Weaver"]] 
        ["Aliens" ["Carrie Henn" "Sigourney Weaver" "Michael Biehn"]] 
        ["Die Hard" ["Alan Rickman" "Bruce Willis" "Alexander Godunov"]] 
        ["Rambo: First Blood Part II" ["Richard Crenna" "Sylvester Stallone" "Charles Napier"]] 
        ["Commando" ["Arnold Schwarzenegger" "Alyssa Milano" "Rae Dawn Chong"]] 
        ["Mad Max 2" ["Bruce Spence" "Mel Gibson" "Michael Preston"]] 
        ["Mad Max" ["Joanne Samuel" "Steve Bisley" "Mel Gibson"]] 
        ["RoboCop" ["Nancy Allen" "Peter Weller" "Ronny Cox"]] 
        ["Braveheart" ["Sophie Marceau" "Mel Gibson"]] 
        ["Mad Max Beyond Thunderdome" ["Mel Gibson" "Tina Turner"]] 
        ["Predator" ["Carl Weathers" "Elpidia Carrillo" "Arnold Schwarzenegger"]] 
        ["Terminator 3: Rise of the Machines" ["Nick Stahl" "Arnold Schwarzenegger" "Claire Danes"]]]) 
    
    (def conn (d/create-conn {:film/cast {:db/valueType :db.type/ref 
                 :db/cardinality :db.cardinality/many} 
              :film/name {:db/unique :db.unique/identity 
                 :db/cardinality :db.cardinality/one} 
              :actor/name {:db/unique :db.unique/identity 
                 :db/cardinality :db.cardinality/one}})) 
    (def all-datoms (mapcat (fn [[film actors]] 
              (into [{:film/name film}] 
               (map #(hash-map :actor/name %) actors))) 
             data)) 
    (def all-relations (mapv (fn [[film actors]] 
              {:db/id [:film/name film] 
              :film/cast (mapv #(vector :actor/name %) actors)}) data)) 
    
    (d/transact! conn all-datoms) 
    (d/transact! conn all-relations) 
    

    Özetle Açıklaması, varlıklar iki tür bu veritabanına filmler ve aktörler (kelime cinsiyet gözardı edilmiş amaçlanan) -ve datoms üç çeşit vardır: :film/name (benzersiz dize)

  • filmi varlık: :film/cast (birden ref)
  • aktör varlık: :actor/name (benzersiz dize)
  • Ben soran bir sorgu oluşturmak istiyoruz

Soru: Tek başına bu N aktörler, ve bu N aktörler sahip olan film, N> = 2 için, tek yıldız olarak ortaya çıktı?

Ör RoboCop Nancy Allen, Peter Weller, Ronny Cox rol aldı ama hiçbir filmi sadece Bunlardan ilki ikisini Allen ve Weller rol aldı. Bu nedenle, aşağıdaki sorgu boş seti üretmek için beklenebilir: Ancak

(d/q '[:find ?film-name 
     :where 
     [?film :film/name ?film-name] 
     [?film :film/cast ?actor-1] 
     [?film :film/cast ?actor-2] 
     [?actor-1 :actor/name "Nancy Allen"] 
     [?actor-2 :actor/name "Peter Weller"]] 
    @conn) 
; => #{["RoboCop"]} 

, sorgu kusurludur herhangi maçlar Allen veya Weller- olmayan herhangi aktörleri dışlaması gerektiğini ifade etmek nasıl bilmiyorum çünkü Yine, sadece Allen ve Weller'in başka aktörler olmadan işbirliği yaptığı filmleri bulmak istiyorum, bu yüzden yukarıdaki sorguyu boş set üretmek için uyarlamak istiyorum. Bu gereksinimi zorlamak için bu sorguyu nasıl ayarlayabilirim?

cevap

2

DataScript'in yoklaması nedeniyle (Mayıs 2016'dan itibaren), 'saf' Datalog'da bir statik sorguyla bunun mümkün olduğuna inanmıyorum.

gitmek My yol olacaktır:

  1. bir film verilmiş, bir yüklem işlevi ekleyin programlı sorgu inşa dökme N aktörleri içermesi gerektiğini bildirmektedir N maddeleri eklemeye, veritabanı ve aktörler kimlikleri kümesi, her filmin sette olmayan bir aktör olup olmadığını bulmak için EAVT dizinini kullanır.

İşte Bir varlığın :film/cast alana göre filtreleme datoms birlikte yüklem eğlenceli ve d/entity kullanabilirsiniz temel bir uygulamasını

(defn only-those-actors? [db movie actors] 
    (->> (datoms db :eavt movie :film/cast) seq 
    (every? (fn [[_ _ actor]] 
       (contains? actors actor))) 
    )) 

(defn find-movies-with-exact-cast [db actors-names] 
    (let [actors (set (d/q '[:find [?actor ...] :in $ [?name ...] ?only-those-actors :where 
          [?actor :actor/name ?name]] 
         db actors-names)) 
     query {:find '[[?movie ...]] 
       :in '[$ ?actors ?db] 
       :where 
       (concat 
       (for [actor actors] 
        ['?movie :film/cast actor]) 
       [['(only-those-actors? ?db ?movie ?actors)]])}] 
    (d/q query db actors db only-those-actors?))) 
+0

Gecikme için özür dilerim (ve sizi rahatsız etmek için özür dilerim)! Sorguda * sadece-o-aktörler? * * Gibi bir kontrol koymanın herhangi bir yararı var mı? Https://gist.github.com/fasiha/647a48420770536a4fa952a4b38f69d7#file-stackoverflow-clj-L97-L116 başına sorgunun dışındaki tüm isabetleri ve işlem sonrası işlemleri almanız mümkün müdür? Bu uygulama 'datoms' rotası gitmeyecek mi? –

+0

Uygulamanız da iyi görünüyor! Akıllıca farklı bir kullanımınız var. Bir optimizasyon olarak, belki de sıralamadan daha verimli olan farklı aktörlerin sayısını sayabilirsiniz. Datom kullanıp kullanmama hakkında: Performans hakkında herhangi bir iddiada bulunmayacağım, ölçütleri çalıştırmalısınız. –

+0

Şu anda olduğu gibi kodda bir veya iki ek şeyi temizlemek zorunda kaldım: https://gist.github.com/fasiha/647a48420770536a4fa952a4b38f69d7#file-stackoverflow-clj-L60-L85 (eğer güncellemek isterseniz) cevap) ama işe yarıyor! Teşekkürler!! –

0

bu. Bu yaklaşım, Datascript'in olumsuzluğu desteklemedikçe (değil işleci vb.) Çok daha basit görünüyor.Senin durumunda DataScript here

[{:db/id 1 :name "Ivan" :age 10} 
{:db/id 2 :name "Ivan" :age 20} 
{:db/id 3 :name "Oleg" :age 10} 
{:db/id 4 :name "Oleg" :age 20}] 

... 

(let [pred (fn [db e a] 
      (= a (:age (d/entity db e))))] 
    (is (= (q/q '[:find ?e 
       :in $ ?pred 
       :where [?e :age ?a] 
         [(?pred $ ?e 10)]] 
       db pred) 
     #{[1] [3]}))))) 

test durumunda sıranın (= a (:age (d/entity db e)) de

Bak, yüklem vücut, d/entity performans açısından bu

(clojure.set/subset? actors (:film/cast (d/entity db e)) 

gibi bir şey olabilir çağrı hızlıdır, çünkü endeksle bir aramadır.