ArangoDB - แบบสอบถามตัวอย่าง AQL

ในบทนี้เราจะพิจารณาตัวอย่างแบบสอบถาม AQL บางส่วนในไฟล์ Actors and Moviesฐานข้อมูล. คำค้นหาเหล่านี้อ้างอิงจากกราฟ

ปัญหา

ให้คอลเลกชันของนักแสดงและคอลเลกชันของภาพยนตร์และคอลเลกชัน actIn edge (พร้อมคุณสมบัติปี) เพื่อเชื่อมต่อจุดยอดตามที่ระบุด้านล่าง -

[Actor] <- act in -> [Movie]

เราจะได้รับอย่างไร -

  • นักแสดงทุกคนที่แสดงใน "movie1" OR "movie2"?
  • นักแสดงทุกคนที่แสดงทั้ง "movie1" และ "movie2"?
  • ภาพยนตร์ทั่วไปทั้งหมดระหว่าง "ดารา 1" และ "นักแสดง 2"?
  • นักแสดงทุกคนที่แสดงในภาพยนตร์ 3 เรื่องขึ้นไป?
  • ภาพยนตร์ทั้งหมดที่มีนักแสดง 6 คนแสดง?
  • จำนวนนักแสดงตามภาพยนตร์?
  • จำนวนภาพยนตร์โดยนักแสดง?
  • จำนวนภาพยนตร์ที่แสดงในระหว่างปี 2548 ถึง 2553 โดยนักแสดง?

วิธีการแก้

ในระหว่างขั้นตอนการแก้ปัญหาและรับคำตอบของคำถามข้างต้นเราจะใช้ Arangosh เพื่อสร้างชุดข้อมูลและเรียกใช้การสืบค้นนั้น ข้อความค้นหา AQL ทั้งหมดเป็นสตริงและสามารถคัดลอกไปยังไดรเวอร์ที่คุณชื่นชอบแทน Arangosh ได้

เริ่มต้นด้วยการสร้างชุดข้อมูลทดสอบใน Arangosh ก่อนอื่นให้ดาวน์โหลดไฟล์นี้ -

# wget -O dataset.js
https://drive.google.com/file/d/0B4WLtBDZu_QWMWZYZ3pYMEdqajA/view?usp=sharing

เอาต์พุต

...
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘dataset.js’
dataset.js [ <=> ] 115.14K --.-KB/s in 0.01s
2017-09-17 14:19:12 (11.1 MB/s) - ‘dataset.js’ saved [117907]

คุณจะเห็นในผลลัพธ์ด้านบนว่าเราได้ดาวน์โหลดไฟล์ JavaScript dataset.js.ไฟล์นี้มีคำสั่ง Arangosh เพื่อสร้างชุดข้อมูลในฐานข้อมูล แทนที่จะคัดลอกและวางคำสั่งทีละคำเราจะใช้ไฟล์--javascript.executeตัวเลือกบน Arangosh เพื่อดำเนินการคำสั่งหลายคำสั่งแบบไม่โต้ตอบ พิจารณาคำสั่งช่วยชีวิต!

ตอนนี้ดำเนินการคำสั่งต่อไปนี้บนเชลล์ -

$ arangosh --javascript.execute dataset.js

ระบุรหัสผ่านเมื่อได้รับแจ้งดังที่คุณเห็นในภาพหน้าจอด้านบน ตอนนี้เราได้บันทึกข้อมูลแล้วดังนั้นเราจะสร้างแบบสอบถาม AQL เพื่อตอบคำถามเฉพาะที่เกิดขึ้นในตอนต้นของบทนี้

คำถามแรก

ให้เราถามคำถามแรก: All actors who acted in "movie1" OR "movie2". สมมติว่าเราต้องการค้นหาชื่อของนักแสดงทุกคนที่แสดงใน "TheMatrix" หรือ "TheDevilsAdvocate" -

เราจะเริ่มด้วยภาพยนตร์ทีละเรื่องเพื่อรับชื่อนักแสดง -

127.0.0.1:8529@_system> db._query("FOR x IN ANY 'movies/TheMatrix' actsIn
OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN x._id").toArray();

เอาต์พุต

เราจะได้รับผลลัพธ์ต่อไปนี้ -

[
   "actors/Hugo",
   "actors/Emil",
   "actors/Carrie",
   "actors/Keanu",
   "actors/Laurence"
]

ตอนนี้เรายังคงสร้าง UNION_DISTINCT จากแบบสอบถาม NEIGHBORS สองรายการซึ่งจะเป็นทางออก -

127.0.0.1:8529@_system> db._query("FOR x IN UNION_DISTINCT ((FOR y IN ANY
'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN
y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true,
uniqueVertices: 'global'} RETURN y._id)) RETURN x").toArray();

เอาต์พุต

[
   "actors/Charlize",
   "actors/Al",
   "actors/Laurence",
   "actors/Keanu",
   "actors/Carrie",
   "actors/Emil",
   "actors/Hugo"
]

คำถามที่สอง

ตอนนี้ให้เราพิจารณาคำถามที่สอง: All actors who acted in both "movie1" AND "movie2". ซึ่งเกือบจะเหมือนกับคำถามข้างต้น แต่คราวนี้เราไม่สนใจ UNION แต่เป็น INTERSECTION -

127.0.0.1:8529@_system> db._query("FOR x IN INTERSECTION ((FOR y IN ANY
'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN
y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true,
uniqueVertices: 'global'} RETURN y._id)) RETURN x").toArray();

เอาต์พุต

เราจะได้รับผลลัพธ์ต่อไปนี้ -

[
   "actors/Keanu"
]

คำถามที่สาม

ตอนนี้ให้เราพิจารณาคำถามที่สาม: All common movies between "actor1" and "actor2". คำถามนี้เหมือนกับคำถามเกี่ยวกับนักแสดงทั่วไปใน movie1 และ movie2 เราต้องเปลี่ยนจุดเริ่มต้น ตัวอย่างเช่นให้เราค้นหาภาพยนตร์ทั้งหมดที่ Hugo Weaving ("Hugo") และ Keanu Reeves ร่วมแสดง -

127.0.0.1:8529@_system> db._query(
   "FOR x IN INTERSECTION (
      (
         FOR y IN ANY 'actors/Hugo' actsIn OPTIONS 
         {bfs: true, uniqueVertices: 'global'}
          RETURN y._id
      ),
      
      (
         FOR y IN ANY 'actors/Keanu' actsIn OPTIONS 
         {bfs: true, uniqueVertices:'global'} RETURN y._id
      )
   ) 
   RETURN x").toArray();

เอาต์พุต

เราจะได้รับผลลัพธ์ต่อไปนี้ -

[
   "movies/TheMatrixReloaded",
   "movies/TheMatrixRevolutions",
   "movies/TheMatrix"
]

คำถามที่สี่

ตอนนี้ให้เราพิจารณาคำถามที่สี่ All actors who acted in 3 or more movies. คำถามนี้แตกต่างกัน เราไม่สามารถใช้ประโยชน์จากฟังก์ชันเพื่อนบ้านที่นี่ได้ เราจะใช้ edge-index และคำสั่ง COLLECT ของ AQL ในการจัดกลุ่มแทน แนวคิดพื้นฐานคือการจัดกลุ่มขอบทั้งหมดตามstartVertex(ซึ่งในชุดข้อมูลนี้เป็นตัวแสดงเสมอ) จากนั้นเราจะลบนักแสดงทั้งหมดที่มีภาพยนตร์น้อยกว่า 3 เรื่องออกจากผลลัพธ์เนื่องจากที่นี่เราได้รวมจำนวนภาพยนตร์ที่นักแสดงแสดงไว้ -

127.0.0.1:8529@_system> db._query("FOR x IN actsIn COLLECT actor = x._from WITH
COUNT INTO counter FILTER counter >= 3 RETURN {actor: actor, movies:
counter}"). toArray()

เอาต์พุต

[
   {
      "actor" : "actors/Carrie",
      "movies" : 3
   },
   
   {
      "actor" : "actors/CubaG",
      "movies" : 4
   },

   {
      "actor" : "actors/Hugo",
      "movies" : 3
   },

   {
      "actor" : "actors/Keanu",
      "movies" : 4
   },

   {
      "actor" : "actors/Laurence",
      "movies" : 3
   },

   {
      "actor" : "actors/MegR",
      "movies" : 5
   },

   {
      "actor" : "actors/TomC",
      "movies" : 3
   },
   
   {
      "actor" : "actors/TomH",
      "movies" : 3
   }
]

สำหรับคำถามที่เหลือเราจะพูดคุยเกี่ยวกับรูปแบบการสืบค้นและให้เฉพาะคำถามเท่านั้น ผู้อ่านควรเรียกใช้แบบสอบถามด้วยตัวเองบนเทอร์มินัล Arangosh

คำถามที่ห้า

ตอนนี้ให้เราพิจารณาคำถามที่ห้า: All movies where exactly 6 actors acted in. แนวคิดเดียวกับในแบบสอบถามก่อนหน้านี้ แต่มีตัวกรองความเท่าเทียมกัน อย่างไรก็ตามตอนนี้เราต้องการภาพยนตร์แทนนักแสดงดังนั้นเราจึงส่งคืนไฟล์_to attribute -

db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER
counter == 6 RETURN movie").toArray()

จำนวนนักแสดงตามภาพยนตร์?

เราจำไว้ในชุดข้อมูลของเรา _to ตรงขอบตรงกับภาพยนตร์ดังนั้นเราจึงนับว่าบ่อยแค่ไหน _toปรากฏขึ้น นี่คือจำนวนนักแสดง แบบสอบถามเกือบจะเหมือนกันกับคำค้นหาก่อนหน้านี้without the FILTER after COLLECT -

db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN
{movie: movie, actors: counter}").toArray()

คำถามที่หก

ตอนนี้ให้เราพิจารณาคำถามที่หก: The number of movies by an actor.

วิธีที่เราพบวิธีแก้ไขสำหรับคำถามข้างต้นของเราจะช่วยให้คุณพบวิธีแก้ปัญหาสำหรับคำถามนี้เช่นกัน

db._query("FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter
RETURN {actor: actor, movies: counter}").toArray()