 Migration was, in fact, correct. Anybody who's done large-scale data migrations on old legacy databases knows that actually convincing yourself that the migration worked for all of the database rather than most of the database is fraught with peril. Allows the individual changes to be testified, and then it simplifies the promotion of the changes. By isolating these individual changes and composing them, we are effectively versioning the database. And we should have automated scripts associated with each one of these small sets and the collection of all of these steps, which will allow us to take a database that is at the current production level, whether that be in a UAT environment, whether that be in production, and apply those changes to it. And because, just like we do with everything else in this pipeline, first you apply the changes to the development database. And then you apply those same changes into the next stage of your pipeline. And each one of those tests is increasing your confidence in the quality of the migrations and the quality of the updates to the database. So by the time you're actually doing it to the production database, this is not the first time you are making those changes. And so you have increased confidence that this upgrade of the database is really going to work. And I really can't emphasize enough, I don't really think DBAs worry so much about the change to the database. Yes, they probably worry about how the change is going to affect performance, since developers very often don't think about the performance impacts of some of their database changes. But mostly, I think DBAs worry about the migrations. What's happening to the data, because that database is an important asset to the organization, and they're the gatekeepers. And so if something goes wrong with their data, it's the DBAs who are on the line first. And so making sure we understand how to safely migrate databases is really a key part of convincing DBAs that we can in fact evolve databases. There is a book about the subject. This has actually helped in convincing DBAs that they can do this, in part because the people who wrote the book are not just developers, they're people who understand the data world. So the second question I often get asked is, why do we even worry about this? Now, because this is an agile conference, I don't have to convince you that we can't know on day one what our entire data model is going to look like, even necessarily six months down the road, let alone two or five years down the road. So we evolve databases because our data changes, but it's not just our data. And in many ways, what's more important, it is also how we understand our data, how we wanna access our data, how we're gonna use our data and what this data means to us. And when you think about this in the context of how do I know something is going to be a performant configuration, if I'm moving from a system where I have predominant reads and not a great deal of rights to a system where all of a sudden that balance has changed, what I have to do to make sure that that database is performant is going to look very different. So even our access patterns, and therefore what the impact of that is on performance can evolve over time. Okay, so let's get a bit more specific. First I wanna talk about document databases. This is one of the category of the aggregate databases and to remind you all what I mean by aggregate is rather than thinking about an individual field, so think about a customer order for example, rather than just thinking about the address field or the name field, when I operate on an aggregate, I am operating on the whole customer order. When I conceptually think about copying and moving and persisting and changing, I'm not thinking about it on the individual field level, I'm thinking about it as an aggregate. And so we're using this aggregate in the same sense that Eric Evans uses it in domain-driven design. This is what we mean by aggregate database. So it's a document that's stored. The document has structure to it. So when we are talking about the document data class, that structure is actually visible to you. In the key value store, you don't necessarily see the structure that's within the blob. In a key value store, you have a key that refers to a value and while some of the key value stores are now allowing some visibility into that blob, conceptually, if you wanna really distinguish these different types, key value store, you've got a blob where you don't really know anything what's in it, whereas in the document database, the structure is visible to you. The structure therefore is also accessible for queries. So you can use the various fields within the structure to retrieve items from the document database. And the structure is also used for indexing. This is another question that's often get asked, well, if you don't have a relational database, how can you build an index? Well, those two characteristics are completely orthogonal and I think it demonstrates to us how much our thinking about persistence mechanisms have been influenced by relational databases where we think something as fundamental as an index could only work in the relational context. So the structure of these documents, you can select which ones of these fields within the structure can in fact be used for indexing. Most of what I'm gonna tell you about right now, although it generally applies across the document class, is gonna be focused on MongoDB. It's one of the major contenders in the document database market. That doesn't mean it's the only one and that there is very little in here that is Mongo specific, except perhaps some of the terminology. So, again, what is a document? You can almost think of this as an object with no methods. If you've been around in the structured programming aspect or era of computer programming, this is just a data structure. This is a collection of fields where you have names associated with the different fields, you have types associated with it, but these documents don't have any methods attached to them. So it's simply a complex data structure. The individual components of this document are key value. So these are effectively named fields. MongoDB actually stores these things in Besan, which is just a binary form of JSON. Not necessarily terribly important. What is important is you retrieve it using a specific query language. So it's not that we don't have a query language. Again, the NoSQL name is pretty bad. It's just we don't have the relational data model and therefore the existing SQL language, which is focused really around relational retrieval, isn't applicable. So what does it mean to query a document database? Well, obviously you have to tell it what you're looking for. So if you have indexes, what is the value of the index that you're looking for? So you are gonna specify effectively the where expression. What am I looking for? That's the fundamental part of the query. In the case of the Mongo query language, you can also specify what order do you want these things to come back in. We often think of things as coming in a particular order in the way that we design them in the database. We have an order by. We can give hints to the optimizer. There is nothing magical about the Mongo query language that will make all of the queries wonderfully efficient. So you can actually give hints to the optimizer much like we can give hints to the query optimizer and the relational world. There's a lot of other stuff in the query language about the way you can specialize this that is well beyond the scope of this talk. But what you get back is a result set. You get a cursor to a series of documents that correspond to the query, whatever query it is that you gave. Okay, I wanna talk a little bit more about indexes and this is going to become a bit more important when we talk about how you might change a document and therefore evolve a document database. When we think about an index in a relational context, I think most people think if I supply an index, that's gonna help me get to everything in my database. Well, we don't have the same kind of restriction in a document database. So if I specify a field to be an index, what if that field doesn't appear in a particular document? What does an index mean in that context? And so in Mongo, you have sparse indices which is you explicitly saying this index should only retrieve things that have this particular field. Now, what does a sparse index imply then? If you query on the basis of a particular index and the document you really want doesn't have that field in it, it is not going to come back. So when you think about sparse indices, you have to understand not just the structure of your database, but how it is currently populated, understand the behavior that you're going to get with that particular index. So now we're in a project and we have a Mongo database within our project and we're on iteration N plus one and we need to change our database. What do we need to think about from the perspective of evolving this representation, assuming once again that we've got an instance of this running in production so somebody out there really cares about the data that's in the current instance of the database. The first thing to remember about a document database and this is in fact part of its power is all the data doesn't have to look the same. Every document doesn't have to have all of the same fields. This is part of the strength of the document database but it's something that you have to think about in terms of performance. So there is a sense in which this feels really liberating. Well gee, I need to add a field. Cool, all I have to do is add it. You don't have to muck with any of the database stuff and I can just go on. But you have to think about what does it mean if some documents have that field and others don't. Since queries can return subsets you can start to think about how might I partition things within my database. So I might have some kind of, let's say I'm working in a product catalog and I have different product categories and I'm an electronics retailer and so cell phones have all kinds of additional things you have to keep track of with a cell phone that you really don't have to for a DVD or for a computer. And so you can think about I can come up with these categories. I can still have one universal product catalog but I can have an alternative structure that represents all of this interesting stuff I need for cell phones. And then if now I'm suddenly carrying a completely new kind of thing, I can say okay well in looking at my data it makes sense for me to now say I've got a new product category and this is what the structure is for this particular product category. And so you can structure your queries in such a way that if you're looking for cell phones the fact that you've added a completely different category for various brands of rice is not going to impact anything that you do with your cell phones. It's also easy in this context to ignore added information. You do have to understand how you are processing your N pound documents but even if you are working with a document that has fields that have been added this particular structure makes it easier for you to ignore that added information if it doesn't apply to you. However if you're going to add something that you want to actually consider as a non-sparse index you have to then think about I'm going to have to migrate the other data. If I suddenly have something that I want to ensure indexes across my entire document database this should seem obvious but it does mean I have to migrate things, I have to decide what am I going to add to that to each one of those individual documents to give it the proper value for that index fields. What sometimes then happens with this there are questions about do I migrate my database all at once? Do I migrate it as I access it? Do I migrate it based on some slice? Those are all different possibilities depending on how big your database is. We've had situations where you might actually want to consider a version number that will help you understand where your particular document is within this evolutionary path. So these are some of the things that you need to think about even though on the surface it might be oh okay I can slap anything in this in this database that I want and Mongo is not going to put any requirements on you in terms of how you structure this but this is what you have to think about from the context of your data model and how you're representing that in Mongo. An important part of this is don't forget the law about how we communicate with information sources. You want to be a tolerant reader and a magnanimous writer. You want to be very, very careful and respectful about what you write and you want to be very liberal about what you read. You want to make sure that you accept everything possible in terms of reading as long as it gives you what you want and this applies in thinking about how you're going to structure queries and how you're going to structure your documents within a document database. Okay so what about testing? And when we talk about testing we are talking about primarily testing in this context whether the migration worked. Whether and whether the new access code that we're putting into our system will work with the newly configured database. So first thing we have to think about obviously is the indexes. Have we properly accounted for indexes? If we are introducing something that needs to be a universal index we need to decide what that default value will be or what the proper value will be for all of the existing documents in the database that don't currently have that field and we have to test whether or not our migration appropriately provides that value across the database. We also need to look at any place that is more particular about what it reads on the particular documents and ensure that the new structure hasn't broken any of the access code in any way. Now there are lots of things we can do about how we structure our code to ensure that doesn't happen but these are the primary changes that you are going to have in working with a document database. You're either going to be adding a field and that field may or may not be an index. You might be deleting a field but that's usually, that isn't as common in an enterprise context. They don't like to throw data away. They might rename it but things enterprises don't like to give up data they have so that is a less common occurrence. You're more likely going to be adding particular fields and that's where you have to think about does the migration properly maintain the semantics of documents that are not supposed to be altered by the migration and if in the case of an absolute index do I have the proper values and therefore do my queries return what it is I want. Now I brought up the product catalog earlier because I actually think this is a very good example of where a document database comes in handy. If you think about things from a retail context retailers have in general lots of different kinds of products. One of the things that retailers often want to do as well is say, well if you buy a new DVD player you can get three DVDs for free and so even though you have very different characteristics of these different kinds of products you do have to have them in some kind of compatible structure so you can structure these promotions around them. Having worked with various product catalogs it can be incredibly frustrating when you are looking at trying to fit this into a relational model because all products are not equal and so you end up pulling all of the tricks that we've learned on how do you make a more rigid schema flexible enough to take into account, you know a cell phone has all of these different things. You might have different characteristics on your refrigerators or maybe you need to track energy efficiency to give some report to some government entity on whether or not your store is green enough in its sales. So this is an area where the product catalog actually I think takes advantage of the flexibility that you have within the document data structure but it also does help you understand as you start to think about things like promotions why these in fact should be in a unified database not I've got a mobile phone database over here and a DVD database over there. So that's document databases. Now what about graph databases? Graph databases are something completely different. When you think about a graph database first we need to step back and okay well what is a graph? Well graphs have nodes and edges and all kinds of things like that. So how would you represent your data in a graph? And I've had many spirited conversations with some of the people from Neo4j on just how widely applicable graph databases are. But there is one thing that I agree with them absolutely there is data that is very clearly graph and that the only representation that it really makes sense is to think about this as a graph. So when you're looking at your problem well how would you model your particular data in a graph? Well the first things you have are nodes and nodes are the building blocks if you will of graphs and very often they have some form of identity so if you wanna use a social graph it's one of the more common things that people think about as graphs. The nodes are you and you've got an identity and there are probably properties associated with you. And then very important in this graph context are the relationships and this is how we move from one place to another in a graph. So you can ask who are my friends and there is a friend relationship that goes from me to the other nodes of the people who represent my friends in the social graph and again those things can be typed. So I could categorize my friends as maybe friends from work versus friends from high school versus friends from my neighborhood. So you can have properties, you can type these edges and so you can have a particular type friend which has particular modifiers friend from high school, friend from work, et cetera. And the key thing that you do with a graph is what you're really interested in is not so much a node and not so much the edges that go out of a particular node but the paths through the graph. How do I connect to my sister, to the people that she went to school with? What are the paths through this graph? So the important information when you're thinking about a graph database is not so much the nodes that are in it but the paths that you can follow. And paths as you traverse a path you are going through both nodes and edges. And those are both important pieces of information when you think about the query is what nodes have I captured along the way on this path and what relationships along that path have I had to exploit to get there? And so when we talk about querying in a graph database what we are doing is we are constructing a request for a path. Do you have a path starting from here that looks like this? That is what a query is in a graph database. It's a very different notion of query which is why if you've not worked with graphs before it might be a difficult transition to go to a graph database because you have to think about your data model very differently. And you have to think about what a result is very differently than you do in other contexts. And that way some of the other aggregate based NoSQL databases are more natural because we think about objects. Graphs are not objects. Graphs are something very different. Neo4j is probably the best known example. And so where I need to be specific or use a specific name for that I will use Neo4j terminology but everything I'm gonna say applies to graph databases in general. An edge in a social network would be like a friend. So I have a friend, there's an edge that goes from me to Badri and that might have a specific qualifier that I know him from work. Yes, Badri is the node, friend is the edge. So actually I'll get to that right here. Basic graph concepts. So an edge has a node on either end. Okay, so one of the first things we need to think about when you start talking about searching a graph is how am I going to search it? And there are two primary ways of searching a graph. Either breadth first, which means if I'm starting with me and I have 100 friend edges, I'm going to take one step on all of those edges, collect all of those nodes that are one away from me. And then I'm going to go to this first one in that level one. And I'm going to go one step there and one step there and one step there. So I am going wide but shallow in my search approach. Depth first, on the other hand, says I'm going to go to the first friend and then I'm going to go to their person's first and then I'm going to go to their person's first and I'm going to chase that path as far as I can. And then as soon as I get to whatever constitutes an end, I'm going to back up one and start again. So I'm always going as far away from the node as possible. Now where this matters is it's going to alter what you find because if you say, find me the first, well the first is going to be very different if I'm looking this way or if I'm looking that way. Again, that's not something we necessarily think about when we think about objects. The only time we think about firsts if we're dealing with a sorted collection first might have some meaning. But this whole notion of am I going to go broad or am I going to go deep really isn't something that we necessarily think about in terms of objects until we start to get into things that look like link lists and then you're starting to get into things that look more like graphs. Cycles become a problem in graphs. If I am chasing a path, what does it mean if I come back to myself? Sometimes I might want to be able to explore multiple paths through myself. If I'm interested in only finding unique things I'm going to potentially stop when I get back to myself. So we have to think about and this is one of the things you have to tell the query engine, what do you do when you run across a node that you've run across before and you're traversal? Again, not necessarily something we think a great deal of when we deal with objects. Connected components, when you look at a graph you might find a group of nodes that are all connected to one another and that might be of importance to you. You might have this group where you can say, okay, all of these people know all of these other people. Okay, well that's a component in some way and that might be of interest to you. What actually might be of more interest to you is where's the lone edge that gets out of that particular group? Again, these are concepts that come from graph theory that are of relevance when you start to think about what are the important insights I'm going to try to pull from this graph? What is my data telling me when I look at it in this graph representation rather than in some other representation? Sometimes it matters, directionality of an edge. I might say, Badri is my friend and Badri might decide, well, Rebecca's not my friend. But there are other things, sisters. Much as my sister might like or dislike me, I'm her sister and she's my sister and there's nothing we can do about that relationship. So there are some relationships that are inherently directional. Some of them might be because of time. It doesn't make sense for a father-daughter relationship to be bi-directional necessarily because I can't be my father's father. Some are inherently non-directional like sister. Another thing you have to think about when you're talking about how am I going to transfer my data into this graph model? And sometimes path length matters as well. So maybe I'm looking for the closest. Maybe I'm looking for everything within some degree of separation. Or maybe I'm looking for what's furthest away. So sometimes an important piece of information is not so much that a path exists, but how long the path is. So all of this is about graph data modeling. The standard way to think about this is nodes represent your entities. People, companies, products, places, those are your nodes. And you can have identities associated with that and you can have properties associated with that. And then relationships, well they capture relationships. They capture what it means. How does this particular entity relate to another? I live in a particular house. I work for a particular employer. I went to a particular school. These, those relationships are what we capture on those edges and what you should see from that as well is there doesn't just have to be edges from people to people. They're edges for people to places and people to institutions and organizations. These edges represent how all of the different discrete entities within this data universe that you're talking about correspond with each other. And then paths tell us how different nodes relate to each other through these various relationships. So maybe I want to find all of the people who went to my school and donate money to the International Rescue Committee. I'm chasing lots of different edges in that relationship. So now how do we specify a traversal? This is where we're gonna get a bit more Neo4j specific in any terminology that I use, but the concepts are still the same. And the first thing you have to tell it is what order? Do you want to look broadly first or do you want to chase paths as deep as they go? What edges should you use? So you can specify I want to navigate friend relationships and donor relationships but I don't want to navigate say employed by or educated by specify what kind of relationships you want to chase in this particular traversal. And if there is directionality, what direction you want to go? And uniqueness, this is what tells you what do I do when I run across a node that I've already seen before? How do you want me to handle that? Do you want me to stop? Do you want me to go on in the traversal? And then most very importantly, where to start? When you think about a graph and all of these things I've been talking about, what's a logical beginning? Well, why would I begin it? People rather than schools, rather than places. So all of these traversals, you have to say, how do I find the start? Whether it be a particular node, tell me where I have to start. And then of course, tell me when the traversal is going to end. This is my query and what comes back from those queries are the paths within your data that satisfy that particular traversal. So you know what nodes were visited and you know by what edges, by what relationships those particular nodes were encountered. How do you capture the, just like any query, a query happens at a given point in time. So if I query it twice, I might in fact get two different results because the underlying data has changed. But I'm not sure, it could be the DAG, it doesn't have to be a DAG. But so at a given point in time, you say I want to traverse this graph and that traversal is going to return some particular subset of the graph. Now the graph can change. And you have to query to get, yes. Just like in a different kind of database, every time you look up a customer you're still gonna re-query the customer because something might have changed. Same kind of thing. An interesting question though because very often people somehow think of graphs as being more static than other kinds of data sources. I get LinkedIn requests every day. My social graph changes every day as a result of those requests. But this graph, this graph in its entirely, all the nodes and all the edges is no different than a relational database. You can add to it, you can delete it. Let me do it in a time, okay. So what kinds of ways can it change? Obviously you can add new nodes of the types that you understand, add new edges of the types that you understand. But what we're interested here is the structural changes. So what are the structural changes that might go on in a graph database? Maybe you're gonna add a completely different node type than you've had before. Maybe you're gonna add different kinds of relationships than you've never had before. You might add properties to nodes and edges since both nodes and edges can have properties. You could delete properties. Deleting is, of course, again, not as common because enterprises don't like to throw things away. But this might happen in the context of maybe you're renaming, maybe you're collapsing things. And then you can delete any of the other things as well. You might take away relationships. You might take away a particular node type. Again, that's more likely to be a rename than an actual delete. Yes, you can do that through properties. Yes, yes. Okay, so how do we think about this from the perspective of evolution? The first thing to realize is that in a sense, although the document database is a collection of documents, you can think of those aggregates in isolation. It doesn't make sense to think of a node in isolation from its database. When you start to represent something in a graph, the information is not just part of the graph. It's the graph in its entirety. And so conceptually, you want to think of this entire graph, whatever you're putting in this database, as a single graph. Now, of course, when you're doing a traversal, you're explicitly pulling out one aspect of that graph. But you should still think of this conceptually as a single graph. Properties in this context are used for indexing. So all of what I told you before in terms of how you have to think differently about indices are going to apply when you manipulate properties. Because relationship types are used for traversal, you need to watch out that you don't orphan somebody. Because remember, you specify a start and you specify how you're going to get to things through edges. So unless you know about something as a possible start node, if you take all of the relationships out of it, you have an orphan in your database. You have no way to get to it. Because all of your accesses are through either using it as a start node or finding it in a traversal. So one of the things you need to look out for when you are doing these migrations is, have I created any orphans? If from my application, I know I always started this particular node type, and all of a sudden I have something of a different node type that has no edges or has no incoming edges if all of my traversals are directional, I have an orphan. And part of that migration needs to be asking the question, what do I do with the orphan? Is it something that doesn't apply anymore? Do I need to find some other anchor to tie this orphan to? That's not the kind of problem we generally think about in relational database concepts. But this is something that you have to think about when you start removing edges. Because you only get to things in those two ways. I can be a start node or I can be found on a traversal. And then of course, new paths can result when you add relationships. So when I was trying to think of a, oh, let me talk about testing first. Orphans are a big thing. Now one thing to think about, although for those of us who got to take algorithms courses in university, we had to program graph traversal algorithms and we could get it right or we can get it wrong. Well, just like generally speaking, one doesn't assume that if one gives a SQL query to a database, it's not going to return the stuff that's there. If we are properly specifying a traversal, we shouldn't be worrying about whether that traversal is correct. We need to be worrying about did we specify the right traversal? Did we include all of the proper edges? Did we include the proper end conditions? Things of that nature. So while there is an aspect of people who like to write programs, who want to worry about all of the code that makes something happen, this like SQL is a more declarative representation of a query. Don't worry whether the traversal works or not. That's not your problem. Worry about whether or not you specified the traversal properly. And when you're thinking about migrations, we still have to worry about indices. If you've messed around with the properties and any of the changes that you've made, then you need to think about how your things are indexed. If you've removed edges, you need to worry about orphans. If you've added edges, you potentially need to worry about cycles. Because you might have added a path back to yourself that didn't exist before. So there are lots of different things you have to think about in a graph database as you change it to make sure that your data, this graph, still represents all of the same assumptions that you had for it in the past. Because when you start to think about queries in terms of traversals, different kinds of problems can come up. Now when I was trying to think about an example, everybody talks about the social graph. And I wanted to think of something different. And so I started to think about, okay, well what if you were gonna be building some kind of graph that represented politicians and political parties and donors? And then what would happen if you merged that with some kind of corporate structure on who sat on boards and which companies owned which other companies? And all of a sudden you could conceive of a query that might find is there some kind of improper relationship between this politician and this company through this range of political contributions and boards and all of that sort of stuff? That is a graph problem. You are trying to exploit different kinds of relationships who's sitting on a particular board, which board corresponds to a particular organization, political donations, party affiliation, all of those kinds of things. You're combining very different relationships and you could have had those two very different structures and all you would have to add is a bit of information really about, you know, okay, the people over here, what's their donor profile? And now you can start to find relationships between individuals in influential positions in companies and influential positions in government. That's a different kind of graph problem than what you'll normally hear talked about. Okay, I don't have too much time yet. I just want to make a plea for polyglot persistence. We have talked about polyglot programming. One of the things that I am particularly excited about with NoSQL databases starting to get attention is we can finally start thinking about what constitutes the right persistence mechanism for our data. So we don't have to shoehorn a graph into a relational database. You can represent a graph in a relational database. It can be done. That doesn't mean the things that you want to do with that graph are easier natural to do in a relational database. And so this at least allows us to ask the question, what is the right way to represent this data? Which is, and sometimes that's relational data. There are pieces of data that are very nicely handled with a traditional relational database model and traditional relational databases. This doesn't mean don't ever use a relational database again. It's just, oh, you have data, therefore you put it in a relational database. That's what needs to change. So then the advantages, you've got to fit for your data model. You can think about what is the right way to look at this data. You can optimize it for your access patterns. Do you have heavy reads? Do you have heavy writes? Do you have completely different access patterns where maybe one storage mechanism is right for the rights, but then you want to farm it off to a different kind of data structure for reporting or analytical purposes. You can think about scaling differently because you've got different options. How you scale a graph database is very different than how you scale a document database to a relational database. You can think about what's right for your particular problems for scaling. And very often, if you use the right tool for the job, rather surprisingly, it goes faster. So if you're really worried about time to market by being able to take a little bit of time and decide this is the right way to do this, you can in fact get to market more quickly. However, comma, you got more decisions to make. You actually do have to think about these things where it used to be you didn't because if you had data persist, you put it in the enterprise relational database. That's what you did and you didn't even have to think about it. Thank you for your time. I've got a couple of minutes for questions if anybody has one. Yes, that varies so widely across the different databases because how you map an object onto a document in Mongo is very different than how you might map an object onto a column store. So you'd have to get a whole lot more specific than that. There are tools that make it easier to work with some of these different databases. But I would start with what's the right data model for the persistence and then start to look at what tools are available in that context. Yes, yes. The big question is you have to figure out how you want to represent your data as a document. But it's migrating the data. So the big question is how do you represent it and then how do you decide that you've actually properly migrated the data? But the first question is what should it look like in this new context? It's not the same as migrating from relational to relational because you're changing the underlying business model or underlying data model. Yes. It varies widely. CouchDB, for example, is known for its replication capabilities, but it varies widely across the different ones. React is very well known for its distribution model. So what you have to look at is what's the intersection between the capabilities that you have and the data model that you want. Eventually, all of the databases will have some kind of story around things like replication, but right now, some of them are more concerned about particular problems than others. So you might not be able to find one that has first-class management tools and replication right this instant, but they all know they have to worry about management tools and they all know they have to have a story around replication. Yes. I think it depends on the data model. I think when you think about it initially, it's easy to say, I'm free from the DBA. I'm free from the schema. I'm free from the relational data model. And so it's easy to think, okay, that means it's going to be easier to evolve. But I think it really does depend on what is the underlying conceptual model of your data and how that's tracking on the path. Some changes are actually relatively easy to make in a relational databases. Some changes, when you make them in a graph database, might be incredibly hard. So it's the process that you use to evolve the database helps make it as easy as possible. But depending on how far you're going from your data model, it might be very difficult to make a particular migration or a particular change in a document because you might need some kind of data model that isn't inherently supported. Just like some changes are very easy in a relational database, but if you all of a sudden wanted to get some kind of infinite depth graph traversal, that's going to be really hard to do in a relational database. So it really comes down to what are the properties of your data and how are you trying to change the properties of those data as you evolve? Can be what for evolution? Yeah, I think it's easier to do that in the no SQL databases because you don't have as many of the constraints. However, you might get yourself into a case where the relational database would have given you protection that you really want, that you don't have in that database. But my sense is you do have more flexibility when you're in the no SQL world, but that comes at a cost because the relational world does give you a lot of safeguards that sometimes are actually quite useful. I think what you're asking is do I know of any examples where a graph database is used to manage relationships amongst various documents? I don't know of any. I don't know that there's anything that would preclude that. One of the issues that you would want to be aware of is how do you actually maintain the consistency between the graph database and the document database? And so you're getting into issues, particularly when you think about things like eventual concurrency. If you've got two databases, two data stores, that are related in that way that have different kind of consistency and characteristics or potentially different distribution across your cluster, you might get into some interesting data problems when those things get out of sync. And this is the last question. Or I need consistency rather than eventual consistency. Then you've got to figure out how your system supports eventual consistency. Is it harder to, or actual consistency? Is it harder to do that? Or is it harder to contort your data to put it into a relational database? Okay, well thank you very much for your time.