|
| 1 | +CREATE TABLE MOVIES ( |
| 2 | + MOVIE_ID NUMBER, |
| 3 | + TITLE VARCHAR2(400), |
| 4 | + GENRES JSON, |
| 5 | + SUMMARY VARCHAR2(16000) |
| 6 | +); |
| 7 | + |
| 8 | +CREATE TABLE MOVIES_CUSTOMER ( |
| 9 | + CUST_ID NUMBER, |
| 10 | + FIRSTNAME VARCHAR(200), |
| 11 | + LASTNAME VARCHAR(200) |
| 12 | +); |
| 13 | + |
| 14 | +CREATE TABLE WATCHED_MOVIE ( |
| 15 | + DAY_ID TIMESTAMP(6), |
| 16 | + MOVIE_ID NUMBER, |
| 17 | + PROMO_CUST_ID NUMBER |
| 18 | +); |
| 19 | + |
| 20 | +CREATE TABLE WATCHED_WITH ( |
| 21 | + ID NUMBER, |
| 22 | + WP_ID NUMBER, |
| 23 | + WATCHER NUMBER, |
| 24 | + WATCHED_WITH NUMBER, |
| 25 | + DATE_WATCHED TIMESTAMP(6), |
| 26 | + MOVIE_ID NUMBER, |
| 27 | + WATCH_PARTY_NAME VARCHAR(200) |
| 28 | +); |
| 29 | + |
| 30 | +INSERT INTO MOVIES (MOVIE_ID, TITLE, GENRES, SUMMARY) VALUES |
| 31 | + (1, 'Inception', '{"Action": "Sci-Fi"}', 'A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.'), |
| 32 | + (2, 'The Matrix', '{"Action": "Sci-Fi"}', 'A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.'), |
| 33 | + (3, 'The Godfather', '{"Drama": "Crime"}', 'The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.'), |
| 34 | + (4, 'Titanic', '{"Romance": "Drama"}', 'A seventeen-year-old aristocrat falls in love with a kind but poor artist aboard the luxurious, ill-fated R.M.S. Titanic.'), |
| 35 | + (5, 'Toy Story', '{"Animation": "Adventure"}', 'A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy''s room.'); |
| 36 | + |
| 37 | +INSERT INTO MOVIES_CUSTOMER (CUST_ID, FIRSTNAME, LASTNAME) VALUES |
| 38 | + (101, 'John', 'Doe'), |
| 39 | + (102, 'Jane', 'Smith'), |
| 40 | + (103, 'Sam', 'Wilson'), |
| 41 | + (104, 'Emily', 'Clark'), |
| 42 | + (105, 'Michael', 'Johnson'); |
| 43 | + |
| 44 | +INSERT INTO WATCHED_MOVIE (DAY_ID, MOVIE_ID, PROMO_CUST_ID) VALUES |
| 45 | + (TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 1, 101), |
| 46 | + (TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 1, 102), |
| 47 | + (TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 1, 103), |
| 48 | + (TO_TIMESTAMP('2024-10-31 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 2, 101), |
| 49 | + (TO_TIMESTAMP('2024-09-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 3, 101), |
| 50 | + (TO_TIMESTAMP('2024-10-31 09:15:23.654321', 'YYYY-MM-DD HH24:MI:SS.FF'), 2, 102), |
| 51 | + (TO_TIMESTAMP('2024-11-01 16:45:12.987654', 'YYYY-MM-DD HH24:MI:SS.FF'), 3, 103), |
| 52 | + (TO_TIMESTAMP('2024-11-02 18:22:43.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 4, 104), |
| 53 | + (TO_TIMESTAMP('2024-11-03 20:01:00.000000', 'YYYY-MM-DD HH24:MI:SS.FF'), 5, 105); |
| 54 | + |
| 55 | +INSERT INTO WATCHED_WITH (ID, WP_ID, WATCHER, WATCHED_WITH, DATE_WATCHED, MOVIE_ID, WATCH_PARTY_NAME) VALUES |
| 56 | + (1, 101, 101, 102, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 1, 'New Year Party'), |
| 57 | + (2, 101, 101, 103, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 1, 'New Year Party'), |
| 58 | + (3, 101, 102, 103, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 1, 'New Year Party'), |
| 59 | + (4, 102, 101, 103, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 3, 'Doe Watch Party'), |
| 60 | + (5, 102, 101, 103, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 3, 'Doe Watch Party'), |
| 61 | + (6, 102, 104, 103, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 3, 'Doe Watch Party'), |
| 62 | + (7, 102, 101, 104, TO_TIMESTAMP('2024-10-30 12:34:56.123456', 'YYYY-MM-DD HH24:MI:SS.FF'), 3, 'Doe Watch Party'); |
| 63 | + |
| 64 | + |
| 65 | +BEGIN |
| 66 | +DBMS_CLOUD.CREATE_CREDENTIAL ( |
| 67 | + credential_name => 'GRAPH_CREDENTIAL', |
| 68 | + user_ocid => 'ocid1.user.oc1..aaaaaaaan4vamdkpzj4mcayzihhbdbty27bsomnlpmshu5hcy3w6ceqfwieq', |
| 69 | + tenancy_ocid => 'ocid1.tenancy.oc1..aaaaaaaaj4ccqe763dizkrcdbs5x7ufvmmojd24mb6utvkymyo4xwxyv3gfa', |
| 70 | + private_key => 'MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCDoD9ZzA5BMbtx |
| 71 | +7wf/RnIKilbzhTNAtqMlbQD7s5SbxJkG8q5TfdZLFNFMa453czF6ArwmA5XEU2j1 |
| 72 | +5ndunsXNdWJdPUXIIg2E2B1xrvTQ2fK7yxpTzCpTQEIBKcPUrUdGIfP4wssOJJ1m |
| 73 | +NUrR5a9CILWxj26E4OduPFLFSI05uMtXGz510u8MBJMBhcRW2OZPpAozwtJz0sOZ |
| 74 | +hwCKDqZYQQTmFYjqZTdsMbuCef44EU1iuFg6rSMEZI3d65AQ4+beldVVu7iOVTvy |
| 75 | +XoEZpedk8EPGjl9zhRMheOA5unoMfcKvGWPdqUIQXOSyUe5lPu2TlEflAkAyx55d |
| 76 | +FfxSvdcfAgMBAAECggEADon51WpjvLHImaokgP8AA8gKGLYC1kgWN0EWFbddV+Nc |
| 77 | +X9cYiGJi9EIlaEKNJwaTVX3N2IkW1uu7sUW2tYJWKP6pUdE9zwBr69uPTQpdQmCA |
| 78 | +nlut2cm4dx+m6sf5OJm3QLjpYPXrRfGnbS2/yPWM6UoBp85HD+hjx9pj7iS4bMKj |
| 79 | +LT+7CwNgicEw+J6N2omr5qeGaavyUlWQ4tSIZKhCKliBnk7CNvVkJ7z/ywugc9Ns |
| 80 | +Z0vlCrhduP1VpsrvzcXmEIwGSP7Z+L7bTQUkULMtxOE/LXLtDFd/I/HO32qEgbT7 |
| 81 | +Bo0LDRvNC9+fthulJ3wRu1XpyNJm5RMtiywMIzHT0QKBgQC5eIghgjHRBVk3rEyr |
| 82 | +40yTKv7Z+FJcQywsT146QpxpEeTJrCnPMoZwecVkGqkQUMWTwQpYU6dUBnLyqcMl |
| 83 | +FVrrAoYfmvECeCjqWS11281WQCeYzdIDJ328T+wrFHh4RjFh4GmzQQVU6ZiS5iUT |
| 84 | +ylTtaqH+jvdMkjLJXvbz4YUypwKBgQC1rfPSxF5ChFzSsW8LU/whVs/Mtf+LbxJ6 |
| 85 | +j2MeAqzzKng9rEZPP0r8qQmWGrUvsyx0ikslMJC88ZmG+JWHtVkbUVxQckpyfCIz |
| 86 | +971AFLxLZ1+rjFdqAj124MsYndXUyJ16Lg+BShsiCDlair08YcsVt7k0aPS3vTlA |
| 87 | +svOqb6qeyQKBgBlkzFayKbnxnoaF27WJGHnp4Bzd6ADj3Y9vino1lo64OXf3T34j |
| 88 | +785Ejecn00/9jx+sxYrUYUua2nApGCPiqaEVpmF7aFYrN4bmkNfbMWEGxaUhQQjX |
| 89 | +hlqbIr2/PsNQ8P/ypuY5F87JcO9j/V2ZTUl4WReuYWOlfLiffPZlQURvAoGAQqG9 |
| 90 | +3vsuJu8srAlvVJRE0GVqaQYG5zihalnUXFlW3QgieVwJnV71PZ0xat/4u7nXABcI |
| 91 | +YGdjbiidyia5kMAuIhrA5LBGJZ7pXG3r9uij9nO/Xsdl9/dCW6suUaTxm8zIFNt3 |
| 92 | +zE9FjEG/5zkjFlY3iYuMXXBw8EJyEQyQ2V2DEiECgYB9NzPtecCBkcFVgvSaLlAy |
| 93 | +hK4aQ4EFNe9tzK8v/J0UDNehJPHaapqfnc67o2dQaKdgW61R4IZTiR8B3GUB46Zm |
| 94 | +JZGZDfyPVx/V2lo12vm+TaPntdgcvUBmvtCN/lW7qg3pmsiGOhaJ8Dq+JUkaqDpD |
| 95 | +32uYReMIx+O7R6ua5rmuiA==', |
| 96 | +fingerprint => '5d:cf:7e:55:16:20:e1:60:f6:31:57:4d:ab:f7:35:98'); |
| 97 | +END; |
| 98 | +/ |
| 99 | + |
| 100 | +BEGIN |
| 101 | + -- drops the profile if it already exists |
| 102 | + DBMS_CLOUD_AI.drop_profile(profile_name => 'genai', force => true); |
| 103 | + |
| 104 | + -- Create an AI profile that uses the default LLAMA model on OCI |
| 105 | + dbms_cloud_ai.create_profile( |
| 106 | + profile_name => 'genai', |
| 107 | + attributes => |
| 108 | + '{"provider": "oci", |
| 109 | + "credential_name": "GRAPH_CREDENTIAL", |
| 110 | + "comments":"true", |
| 111 | + "oci_compartment_id": "ocid1.compartment.oc1..aaaaaaaajlby3soifhkjobwner46lpjf5zvwugnzrmdfymtcdu6r2lvtti7a", |
| 112 | + "region":"us-chicago-1", |
| 113 | + "object_list": [ |
| 114 | + {"owner": "ADMIN", "name": "MOVIES"}, |
| 115 | + {"owner": "ADMIN", "name": "MOVIES_CUSTOMER"}, |
| 116 | + {"owner": "ADMIN", "name": "WATCHED_MOVIE"}, |
| 117 | + {"owner": "ADMIN", "name": "WATCHED_WITH"} |
| 118 | + ] |
| 119 | + }' |
| 120 | + ); |
| 121 | + END; |
| 122 | + |
| 123 | + |
| 124 | + |
| 125 | +CREATE PROPERTY GRAPH CUSTOMER_WATCHED_MOVIES |
| 126 | + VERTEX TABLES ( |
| 127 | + MOVIES_CUSTOMER AS CUSTOMER |
| 128 | + KEY(CUST_ID), |
| 129 | + MOVIES AS MOVIE |
| 130 | + KEY(MOVIE_ID) |
| 131 | + ) |
| 132 | + EDGE TABLES( |
| 133 | + WATCHED_MOVIE AS WATCHED |
| 134 | + KEY(DAY_ID, MOVIE_ID, PROMO_CUST_ID) |
| 135 | + SOURCE KEY (PROMO_CUST_ID) REFERENCES CUSTOMER(CUST_ID) |
| 136 | + DESTINATION KEY (MOVIE_ID) REFERENCES MOVIE(MOVIE_ID), |
| 137 | + WATCHED_WITH |
| 138 | + KEY(ID) |
| 139 | + SOURCE KEY (WATCHER) REFERENCES CUSTOMER(CUST_ID) |
| 140 | + DESTINATION KEY (WATCHED_WITH) REFERENCES CUSTOMER(CUST_ID) |
| 141 | + ); |
| 142 | + |
| 143 | +-- Get the Movie title and summary for each movie a customer has watched |
| 144 | +-- We can send this to an LLM as a Graph RAG solution to answer questions like |
| 145 | +--- "What is the genre of {movie} based on this summary" |
| 146 | +SELECT DISTINCT MOVIE_TITLE, MOVIE_SUMMARY |
| 147 | + FROM GRAPH_TABLE( CUSTOMER_WATCHED_MOVIES |
| 148 | + MATCH (c1 IS CUSTOMER)-[e1 IS WATCHED]->(m IS MOVIE) |
| 149 | + COLUMNS (m.title as MOVIE_TITLE, m.summary as MOVIE_SUMMARY) |
| 150 | + ); |
| 151 | + |
| 152 | +WITH prompt_document AS ( |
| 153 | + SELECT |
| 154 | + JSON_OBJECT ('TASK' VALUE 'What is the genre of this movie based on this summary', |
| 155 | + MOVIE_TITLE, |
| 156 | + MOVIE_SUMMARY ) AS prompt_details |
| 157 | + FROM GRAPH_TABLE(CUSTOMER_WATCHED_MOVIES |
| 158 | + MATCH (c1 IS CUSTOMER)-[e1 IS WATCHED]->(m IS MOVIE) |
| 159 | + COLUMNS (m.title as MOVIE_TITLE, m.summary as MOVIE_SUMMARY) |
| 160 | + ) |
| 161 | +) |
| 162 | +SELECT |
| 163 | + DBMS_LOB.SUBSTR(DBMS_CLOUD_AI.GENERATE( |
| 164 | + PROMPT => prompt_details, |
| 165 | + PROFILE_NAME => 'genai', |
| 166 | + ACTION => 'chat' |
| 167 | + ), 4000, 1) AS Answer |
| 168 | +FROM prompt_document; |
| 169 | + |
| 170 | +-- Find customers who are connected through 2/3 watch party connections |
| 171 | +SELECT DISTINCT * |
| 172 | + FROM GRAPH_TABLE( CUSTOMER_WATCHED_MOVIES |
| 173 | + MATCH (c1 IS CUSTOMER)-[e1 IS WATCHED_WITH]-{2,3}(c2 IS CUSTOMER) |
| 174 | + COLUMNS (c1.CUST_ID as c1_cust_id, c1.FIRSTNAME as c1_fist_name, c2.cust_id as c2_cust_id, c2.FIRSTNAME as c2_fist_name) |
| 175 | + ); |
| 176 | + |
| 177 | +-- Find customers who have watched the same movie and are connected in 2/3 hops, excluding results where customer 1 and 2 are the same |
| 178 | +-- This can be sent to an LLM as part of a Graph RAG solution to answer questions like |
| 179 | +-- "Based on this dataset of movies customers who are connected through friends of friends have watched, containing customer IDs, names, movie titles, genres and summaries. How would you describe the movie watching preferences of these users?" |
| 180 | +SELECT DISTINCT * |
| 181 | + FROM GRAPH_TABLE(CUSTOMER_WATCHED_MOVIES |
| 182 | + MATCH (c1 IS CUSTOMER)-[e1 IS WATCHED_WITH]-{2,3}(c2 IS CUSTOMER) -[e2 is WATCHED]-> (m is MOVIE), |
| 183 | + (c1) -[e3 is WATCHED]-> (m is MOVIE) |
| 184 | + WHERE c1.cust_id <> c2.cust_id |
| 185 | + COLUMNS (c1.CUST_ID as c1_cust_id, c1.FIRSTNAME as c1_fist_name, c2.cust_id as c2_cust_id, c2.FIRSTNAME as c2_fist_name, m.title as movie_title, m.genres as movie_genre, m.summary as movie_summary) |
| 186 | + ); |
| 187 | + |
| 188 | + |
| 189 | +-- Create the JSON object with task and result set |
| 190 | +WITH prompt_document AS ( |
| 191 | + SELECT |
| 192 | + JSON_OBJECT( |
| 193 | + 'TASK' VALUE 'Based on this dataset of movies customers who are connected through friends of friends have watched, containing customer IDs, names, movie titles, genres and summaries. How would you describe the movie watching preferences of these users?', |
| 194 | + 'PROMPT_DETAILS' VALUE JSON_ARRAYAGG( |
| 195 | + JSON_OBJECT( |
| 196 | + 'c1_cust_id' VALUE c1_cust_id, |
| 197 | + 'c1_fist_name' VALUE c1_fist_name, |
| 198 | + 'c2_cust_id' VALUE c2_cust_id, |
| 199 | + 'movie_title' VALUE movie_title, |
| 200 | + 'movie_genre' VALUE movie_genre, |
| 201 | + 'movie_summary' VALUE movie_summary |
| 202 | + ) RETURNING CLOB |
| 203 | + ) RETURNING CLOB |
| 204 | + ) AS prompt_details |
| 205 | + FROM GRAPH_TABLE( |
| 206 | + CUSTOMER_WATCHED_MOVIES |
| 207 | + MATCH (c1 IS CUSTOMER)-[e1 IS WATCHED_WITH]-{2,3}(c2 IS CUSTOMER) -[e2 is WATCHED]-> (m is MOVIE), |
| 208 | + (c1) -[e3 is WATCHED]-> (m is MOVIE) |
| 209 | + WHERE c1.cust_id <> c2.cust_id |
| 210 | + COLUMNS (c1.CUST_ID as c1_cust_id, c1.FIRSTNAME as c1_fist_name, c2.cust_id as c2_cust_id, c2.FIRSTNAME as c2_fist_name, m.title as movie_title, m.genres as movie_genre, m.summary as movie_summary) |
| 211 | + ) |
| 212 | +) |
| 213 | +SELECT |
| 214 | + DBMS_LOB.SUBSTR( |
| 215 | + DBMS_CLOUD_AI.GENERATE( |
| 216 | + PROMPT => prompt_details, |
| 217 | + PROFILE_NAME => 'genai', |
| 218 | + ACTION => 'chat' |
| 219 | + ), |
| 220 | + 4000, |
| 221 | + 1 |
| 222 | + ) AS Answer |
| 223 | +FROM prompt_document; |
0 commit comments