Social Network Matchmaking
The Social Network Matchmaking App will be an android application that will allow users to promote matchmaking within their social networks. The app will be created using Java, Google Firebase, NodeJS, and Neo4j.
- 1 Links
- 2 Project Proposal
- 3 Design and Solutions
- 4 Results
- 5 Next Steps
- 6 References
Online matchmaking has become much more popular in recent years driven by the popularity of online services such as Tinder and Match.com. Most of these apps operate on exposing you to as many people as possible whether that is through geolocation (Tinder, Bumble, etc.) or preferences (Match.com, EHarmony). The central idea behind the Social Network Matchmaking app is to connect individuals to others within their own social networks. Ideally their would be a few crucial benefits to this such as self moderated behavior and better thought out matches.
A common complaint for women in online dating apps is that men will send unwanted crass or explicit messages. Ideally this behavior could be reduced by removing anonymity from the process. For every person that is connected, they are aware that their behavior might be relayed back to their social network.
Another complaint of apps that are based on generating many matches is that the value of an individual match is extremely low. Ideally people that know both people will be able to give a more informed assessment which will lead to better matches, better conversations, and ultimately better relationships.
The planned app will contain two main features: connect with people you know and matching people in your network together.
Connecting with people in Network
Users can search for their friends and send friend requests to them.
Matching people in your network
Users will be able to match their 1st degree connections with other 1st degree connections in their network. When users do this, both of the matched persons will be alerted that someone has matched them together. As more people match them together, they can see that more people believe they would be a good match. Users that have been matched can also at anytime signal that they want to chat with the person they were match with and if both people accept then a chat will be opened between them.
The app will be develop for the android using a combination of Java, Firebase, NodeJS, and Neo4j.
Java is the primary language used to develop android applications. Also considered was the language Kotlin but the decision was ulimtately made to go with Java as I am more familiar with Java and want to prioritize time towards building the backend.
Firebase is a Backend As a Service (BaaS) offered by google. Using firebase will for easy implementation of authentication and database service. Many features of the app such as signing up and maintaining friends list will be handled by Firebase and allow for more time to be devoted to implementing the core features of the app. Firebase uses a NoSql structure. The entire backend could be placed on Firebase but given the complexity of a social network structure and the exponential increase as it gets larger, another database will be used to supplement firebase.
NodeJS and Express will be used as the backend web server and to build the API logic. NodeJS was chosen due to the past experience using it and because of the great support it has for Neo4j.
Neo4j is a graph based database. Neo4j was chosen as the primary database because it was developed with graphs in mind unlike relational databases and has key core functionality built in that will allow for easier implementation of features. It was also chosen because I have no experience using graph databases and I believe that this experience should be a learning one. As I'm unfamiliar with Neo4j, some time will be needed to evaluate the full list of features and ensure that it is possible. Something that should be completed by the final proposal deadline.
The anticipated budget for this project is 0$. This might change if free tier hosting limits in Amazon AWS or Firebase are exceeded.
Design and Solutions
Registration and Login
The first step of creating the app was implementing user authentication and account creation. This feature was a good starting point because it allowed me to become familiar with building Android UI and working with activities. The backend of this feature was implemented using Firebase. Google Firebase has an authentication module that produces a unique user id and handles user authentication and login. Using it in the app was as easy as importing the approbate libraries and learning to use the Firebase api.
On the front end I built a registration page and login page in Android studio using XML and Java. At this stage it was very important to to decide exactly what information is important for users to provide. Because this is ultimately a dating app I decided that the most basic information needed included user's names, ages, location, and gender. We also take user input for an email address and password and pass everything along to to the Firebase authentication api. Whenever a user is created, Firebase assigns them a unique ID. This ID is used throughout to ensure unique friend connections and matches. We also add the user to the FirebaseFirestore database. The Firestore database is a NoSQL database that use a nested hierarchy to store information. We use this to store the user's info. We store the majority of user information here because it is less computationally expensive to retrieve that data from this database. When we add a user we also add them to the Neo4J database. The Neo4j database uses a system of nodes and edges to store information about users. Nodes consist of labels and we can also store information within the node. We label our user nodes as Persons and we also label them by their gender. In addition to this we pass along the ID and the names.
The Neo4j database is much larger and much more computationally extensive than relational databases and because of this we don't want to use it as our primary database. The Neo4j database is also not well suited for certain tasks. Things like chat would not work well in a graph database. These are all things I have to keep in mind.
The creation of the api for the Neo4j database is more intensive than the Firebase API. To access the database from online we have to use a web server and we need to use a server side language to communicate between the API, the app, and the database. To accomplish this we use Amazon AWS EC2 cloud server along with NodeJS and Express. Using express we can create 'routes' that make it very easy to process url requests to our server. We structure these routes based on the three core functionalities we will be using our server for: creating users, handling friending features, and handling matching features. We also install Neo4j in the server. This allows us to make calls to the server from online using ports. This also allows us to use Neo4j's interactive database explorer in the browser. This helps to quickly check the information we are placing in the database.
(Labels: Person, Gender)
"name": <String>, "id": <String>
"age":<String> "city":<String> "name": <String>, "gender": <String> "img_url":<String>
Moving on I next added functionality for the addition of friends for users. This is is crucial to the app because the core functionality involves matching your friends with your other friends. Adding friends was created both in Firebase and Neo4j although we only really use the Neo4j to add the friends. To create friends in Neo4j we break the process into 3 steps. First users have to be able to send friend requests to users, then users have to be able to accept friend request, and finally users need to be able to see a list of their friends. In the UI for the app we break these actions into two tabs. We have one tab listing all friends for the user. The second tab prints a list of all users and allows the user to send a request through a button press. The second tab also list all friend request a user has received and allows for acceptance or denial. In our backend we handle the friend requests by creating an edge in between nodes. We pull all nodes connected by a friend request edge of the user to get the list of friend request. Upon acceptance of a request, we destroy this request edge and replace it with a friend edge.
We also created a friend list in FirebaseFireStore because we wanted to reduce the amount of queries that we sent to the Neo4j server. By having the list in Firebase we can easily pull a list of friends from there. Especially as the number of friends grows, this would make it easier to process this request.
For Matching we used Neo4j. Matching worked similarly as the friending concept except that instead of a user directly sending a request, a friend of the two users would do it. This broke our process up for matching into the following:friend of users must match users, both users must accept, chat functionality must be enabled between matched users. This is also created a unique issue in that we want to be able to keep track of exactly who has endorsed a match. To accomplish all of this I incorporated the use of a "match node". Using this match node I would keep track of who had been matched within the node and use edges to the node to denote whether someone endorsed the connection or not. This also made it easier in terms of retrieval. Getting the number of endorsers was as easy as counting connections to the match node. Deciding when a match had been successfully completed required me to evaluate 2 states: Either both had accepted or one user had rejected the pairing. I didn't want to evaluate this everytime I pulled information from Neo4j so I also created a "Match Complete" node that every node would point to when it was complete. Users would only be shown matches that were still open and upon acceptance they would either accept the match which changed the edge to node or they would complete the match which would also create an edge to the Match Complete node and open chat functionality if applicable.
I implemented the chat feature using Firebase Realtime Database. Firebase Realtime Database differed from the FirebaseFirestore in that it is real time and also follows a different NoSQL structure. It is still just a nested hierarchy of information however. I designed the UI so that users would see a list of individuals to chat with. Upon selecting an individual they would be shifted to a chat room where they could message one another. Using the realtime database allowed for realtime updates. I created the backend using a heiracrhcy of chatrooms. Each chatroom was given a unique ID. I created a list of chat room IDs alongside user information in Firebase Firestore to keep track of who they were allowed to chat with. I used this list to populate the UI list. Inside the chat room heiracrhcy chats are ordered by a sequential key that increments every time a new chat is made. I keep track of which user sent the message and the contents of the message.
Firebase Database Chat Schema
Chat ID <Int> Message Number <Int> "ID": <String> "Name":<String> "Message":<String>
Ultimately the main functions of the app were completed. However due to time constraints the app has several issues.
For one the UI is terrible and bland and rife with tiny errors that can make it a nightmare to use. For example I didn't have time to implement notifications for every action that a user takes. So a user might hit a button a some action will happen on the backend but the user will not be alerted to this. In many places the UI will also not shift properly which is veery important from a user perspective.
The app is also just not very fun to use at all. I can chalk this up to the core functionality of the app being too bare on its own to elicit excitement from users. I realize after building it that the UX is very important in keeping users engaged and actually creating a product that depends on having users use it for the purpose to actually make sense. Looking at similar apps such as Tinder, Bumble, or OKCupid, I realize they have certain ways they gamify the process to make it more enjoyable to users. My app has none of this and I think it would be a crucial element to be added.
Over the course of building this app I ended up using three different databases which present it's own set of unique challenges. All of the databases have different loads restraints and different structures. While each was useful on its own for specific functionality, it was a nightmare to actually learn how to use them all and have to restructure my data uniquely for each app. Each app also had severe limitations that were at times very difficult to get through. Also in terms of moving data in between sources, it is time consuming to develop three different injection methods for three different databases.
Neo4j scaling issues
Neo4j turned out to be great at graph functionality but the size of it ultimately turned me off to using it. This was partially because I was using a free version on a free Tier service of Amazon AWS. Neo4j frequently reminded me that it did not have the standards it wanted to have maximum capability. To put this in perspective, Neo4j requested 8 GB of ram at a minimum and the ability to use 40,000 reads and writes simultaneously. My database had 2GB of ram and I gave it 1024 reads/writes. This produced a sense of dread in me whenever I used the database because I feared I would put too much data inside it of and it grow large enough that Amazon would begin charging me money. The actual cost of running a "real" Neo4j server was outside the realm of my pockets. If I was to turn this into a production app, I don't think that I would use Neo4j at all. Neo4j's cypher language turned out to be extremely easy to use however. I didn't have the time to get to the actual fun tasks of using graph algorithms to create better matches. In the future I think Neo4j would be a great way of quickly testing algorithms but I would use a different database with much less scaling costs that could implement some of the graphing functionality I needed.
Lastly upon finishing the app I realized that I spent the vast majority of my time working with android and java. In the future I would likely have gone with a language I was more familiar with as learning on the fly really hurt the UX/UI and took up time that could have been used for better things.