Start webserver med f.eks.
ruby -run -ehttpd . -p8000
Gå ind på http://localhost:8080/
Start webserver med f.eks.
ruby -run -ehttpd . -p8000
Gå ind på http://localhost:8080/
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>CouchDB presentation</title> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta charset="utf-8"> | |
<link rel="icon" href="http://couchdb.apache.org/favicon.ico"> | |
<style> | |
@import url(http://fonts.googleapis.com/css?family=Nunito:100,100italic,300italic,300,400,400italic,700,700italic); | |
@import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700,400italic); | |
body { | |
font-family: 'Nunito'; | |
} | |
.remark-code, .remark-inline-code { | |
font-family: 'Source Code Pro'; | |
} | |
.remark-slide-content { | |
font-size: 25px; | |
background-position: 98% 98%; | |
background-size: 100px; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js"></script> | |
<script> | |
var slideshow = remark.create({ | |
ratio: '16:9', | |
navigation: { | |
scroll: false, | |
touch: false, | |
click: true, | |
}, | |
sourceUrl: 'presentation.md' | |
}); | |
</script> | |
</body> | |
</html> |
class: center, middle
Apache CouchDBTM er:
Dokumenter, måske med forskellige skemaer, kan lægge i samme "tabel" i CouchDB.
Din data er bare JSON.
Man kan have mange databaser, men ingen tabeller.
En database indeholder derfor alt data om et emne. Man kan blande sin data, som man lyster.
F.eks. kan man have:
{
type: 'mail',
uuid: 'abcd1234',
recipient: 'mads.ohm@gmail.com',
subject: 'Hello, World!'
}
og
{
type: 'mail_event',
event: 'opened',
mail_uuid: 'abcd1234'
}
Da det ikke er en relationel database, vil man dog normalt lave dem indlejret:
{
type: 'mail',
uuid: 'abcd1234',
recipient: 'mads.ohm@gmail.com',
subject: 'Hello, World!',
events: ['opened']
}
Gennem views selvfølgelig. Hvad er et view? Javascript!
Et view består af en map
-funktion og muligvis en reduce
-funktion.
En map
-funktion kan være:
function(doc) {
if (doc['type'] == 'mail') {
emit(doc._id, null);
}
}
function(doc) {
if (doc['type'] == 'mail') {
emit(doc._id, null);
}
}
emit
-funktionen her er den specielle.
Vi emitter en grupperingsnøgle og en værdi. Grupperingsnøglen kan være én værdi eller et array.
Værdien vil blive sendt til reduce
-funktionen.
function(doc) {
if (doc['type'] == 'mail') {
emit(doc._id, null);
}
}
Ovenstående map
-funktion vil blot emitte alle mail
-dokumenters interne id
.
Der er ingen værdi, så intet at reducrere på.
Vil vi i stedet blot tælle hvor mange dokumenter af hver type, som er i databasen, kan vi bruge:
function(doc) {
emit(doc['type'], 1);
}
herefter kan vi summere værdier i vores reduce
-funktion.
Vi hiver data ud gennem et HTTP API, f.eks. med:
$ curl -XGET https://couch.lokalebasen.dk/DATABASE/_design/DESIGN_NAME/_view/VIEW_NAME
Vores resultat vil således blot være f.eks.:
[
{"id":"08d0de898bd50d10fb","key":"08d0de898bd50d10fb","value":null},
{"id":"08d0de898bd50d1f47","key":"08d0de898bd50d1f47","value":null},
{"id":"08d0de898bd5270695","key":"08d0de898bd5270695","value":null},
{"id":"08d0de898bd52719af","key":"08d0de898bd52719af","value":null},
{"id":"08d0de898bd5271d12","key":"08d0de898bd5271d12","value":null}
]
OBS. Det er ikke en relationel database.
Vi gør altså ikke ting som:
Article.find_by_id("abcde12345")
Det kan lade sig gøre, ved brug af key
, men det tager linær tid, da den skal søge efter dit dokument.
Der er altså ikke indeks på sådanne ting.
Vores map
- og reduce
-funktioner skal leve et sted.
De lever i et designdokument, som også blot er et dokument i databasen.
...
"views": {
"all": {
"map": "function(doc) {\n if (doc['type'] == 'MailDump') {\n emit(doc._id, null);\n }\n }"
}
}
...
Hvad kan jeg så med en reduce
-funktion?
Mange gange vil man blot have summen af sine emitted værdier. Dette kan gøres med:
function(_key, values, _rereduce) {
var i = 0;
values.forEach(function(value) {
i += value;
});
return value;
}
eller endnu nemmere:
_sum
Vores reduce
-funktion modtager værdier i klumper.
Den kan således få f.eks. 10 værdier ad gangen ud af 100 værdier i alt.
De 10 resultater det så vil give, vil blive smidt igennem reduce
en gang også, men denne gang med rereduce
sat til true
.
Man kan således se om det er emitted værdier eller resultater, som man skal tage hånd om, men reduce
-funktionen skal kunne håndtere begge dele.
I stedet for tabeller, har man således forskellige views, hver med sin map
- og reduce
-funktion.
På den måde kan man hente det data ud man vil.
Det smarte (og det som skiller CouchDB fra andre databaser) ved dette, er at disse er "cached". Når man læser fra et view kan man vælge om man er okay med stale data.
Stale kan have tre forskellige værdier: ok
, update_after
og false
.
Ved ok
får man det cached resultat.
Dette ligger på disk på CouchDB serveren.
Ved update_after
får man igen det cached resultat, men man sætter også en worker igang, som læser ændringer siden sidste cache og kører dem igennem din MapReduce og tilføjer til det cached resultat, så du næste gang får "bedre" data.
Ved false
venter du på at workeren har udført sit job og får derefter data.
Dette er klart den langsomste måde at arbejde, men hvis man ikke kan bruge gammel data, bliver man selvfølgelig nød til dette.
Hvis man skirver sine MapReduces, så man ikke skal lave mere arbejde på data efterfølgende, er det således rigtig hurtigt at hente data.
Views er dyre i form af diskplads, da alt data vil lægge på disken flere gange.
Da alle dokumenter er, vel, dokumenter, kan man også gemme f.eks. HTML- eller andre slags filer.
Man kan vedhæfte disse til sine dokumenter, og således få et attachment.
Vi bruger dette til at gemme afsendte mails (f.eks. https://couch.lokalebasen.dk/lb_mailer/000d512dddbb0c735496fb2a93a85a99/body.html)
Couch har også: