Accessing NCBO Annotator Web Service in C#

The NCBO Annotator allows you to get annotations for (biomedical) text from a number of standard ontologies. For instance, if I want to find the corresponding RadLex codes for ‘abdomen knee’, I can type them into the textbox, and restrict the ontology list to just RadLex.

image

This manual approach works fine if you just want a few sentences annotated, but if you need to annotate multiple sentences in a systematic manner you need to do this programmatically. This is where the annotate web services come in. There are several client examples as well where you can find some sample code in several languages. There is a Java annotator client example, but unfortunately there is no C# example. For something I’m trying to implement I need to (or rather, I prefer to) use C#. Translating some Java code to C# isn’t hard, but in case someone’s looking for a ready-to-use C# example, following is a function/method you can use:

private void GetData()
        {
            Uri address = new Uri("http://rest.bioontology.org/obs/annotator");

            // Create the web request  
            HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;

            // Set type to POST  
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.UserAgent = "Annotator Client Example - Annotator";

            String text = "abdomen knee";

            StringBuilder data = new StringBuilder();

            // Configure the form parameters
            data.Append("longestOnly=" + "false&");
            data.Append("wholeWordOnly=" + "true&");
            data.Append("filterNumber=" + "true&");
            data.Append("withDefaultStopWords=" + "true&");
            data.Append("isTopWordsCaseSensitive=" + "false&");
            data.Append("mintermSize=" + "3&");
            data.Append("scored=" + "true&");
            data.Append("withSynonyms=" + "true&");
            data.Append("ontologiesToExpand=" + "&");
            data.Append("ontologiesToKeepInResult=" + "1057&"); // from http://bioportal.bioontology.org/ontologies/. Use comma sep. list of ont. ids
            data.Append("isVirtualOntologyId=" + "true&");
            data.Append("semanticTypes=" + "&");
            data.Append("levelMax=" + "0&");
            data.Append("mappingTypes=" + "&"); //null, Automatic, Manual 
            data.Append("textToAnnotate=" + text + "&");
            data.Append("format=" + "xml&"); //Options are 'text', 'xml', 'tabDelimited'   
            data.Append("apikey=" + "YOUR_KEY");

            // Create a byte array of the data we want to send  
            byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());

            // Set the content length in the request headers  
            request.ContentLength = byteData.Length;

            // Write data  
            using (Stream postStream = request.GetRequestStream())
            {
                postStream.Write(byteData, 0, byteData.Length);
            }

            // Get response  
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {

                XmlDocument doc = new XmlDocument();
                doc.Load(response.GetResponseStream());

                XmlNodeList nodes = doc.SelectNodes("/success/data/annotatorResultBean/annotations/annotationBean");
                foreach (XmlNode node in nodes)
                {
                    string radlexId = node.SelectSingleNode("concept/localConceptId").InnerText.Split('/')[1];
                    string radlexDescription = node.SelectSingleNode("concept/preferredName").InnerText;
                }

                // Or print to console [uncomment line: doc.Load(response.GetResponseStream());]
                //StreamReader reader = new StreamReader(response.GetResponseStream());
                //Console.WriteLine(reader.ReadToEnd());
            }
        }

You can set breakpoints at radlexID/radlexDescription to see that what you get programmatically is exactly the same as what you get when you type the text directly into website. Per the comment in the code, pick the list of ontologies you are interested in from http://bioportal.bioontology.org/ontologies and pass it as a comma separated list (e.g., if I’m interested in RadLex and Snomed, I’ll use:
“data.Append(“ontologiesToKeepInResult=” + “1057,1353&”);
where 1353 is the ID for Snomed.

Before you can use the web service, you’ll need to sign up at http://bioportal.bioontology.org/accounts/new and get an API key first (which you will then pass as the value for ‘apikey’).

Posted in General | Tagged , , , , , | 1 Comment

Extracting RadLex codes and descriptions from ontology

I was trying to find a flat list of RadLex terms that just had the IDs and descriptions. You can easily browse RadLex using the RadLex Term Browser,  but my requirement was to do a quick lookup using a local database. I couldn’t find something online that was readily available, so I wrote some code to extract just the Id, description fields from RadLex.owl (which you can download from http://www.radlex.org/). In the attached file you can find the list of 34k+ RadLex terms. It’s an Excel file, so you can easily import it into a SQL Server or MySQL  database. I can’t upload a tab delimited .txt file to WordPress.com (see http://en.support.wordpress.com/accepted-filetypes/), so  if anyone needs the file in a different format, just let me know.


8-Nov-2012 update: Seems like there’s a new SQL script that contains all RadLex terms – ftp://ftp.ihe.net/RadLex/documentation.html. I haven’t used it yet, but might be better/newer/more complete than the original Excel file I put together.

Posted in General | Tagged , , | 5 Comments

Good to be Greened!

There’re many many forums that discuss various aspects related to the greencard process. One of the recurring questions seems to be how many publications you need for EB1-EA/NIW. My case is neither since it was filed under EB1-OR., but thought I would just share with you what I had at the time of applying in case someone finds it useful. My impression/understanding based on various forums I’ve read is that the criteria for EB1-EA/NIW is a lot harder since these categories don’t require a job offer. Anyway, this is what I had:

  1. PhD in Computer Science (completed in 2010)
  2. 16 journal publications (9 first author) – mostly international fairly high-impact journals.
  3. 12 conference papers (6 first author)
  4. 13 reviewer invitations (6 direct, 2 on behalf of supervisor, 5 rejected)
  5. 12 awards (8 national/university level awards related to PhD work, 3 travel grants, 1 international recognition where a paper was selected to be included in the Yearbook of Medical Informatics)
  6. 4 emails/threads showing where other researchers had reached out to me asking for my advice/opinion
  7. 103 Google Scholar hits
  8. 60+ citations (excluding self citations) from 17 different countries – got this from Scopus
  9. 14 Pubmed entries (good journals are indexed in Pubmed if you’re in the medical domain)
  10. 2 provisional patent applications (i.e., not granted yet)
  11. 4 recommendation letters (2 from PhD supervisors, 1 from internship mentor, 1 from my project leader in the company)

You need to meet only two out of the following requirements for EB1-OR:

  • Evidence of receipt of major prizes or awards for outstanding achievement
  • Evidence of membership in associations that require their members to demonstrate outstanding achievement
  • Evidence of published material in professional publications written by others about the alien’s work in the academic field – (citations?)
  • Evidence of participation, either on a panel or individually, as a judge of the work of others in the same or allied academic field – (peer-reviewed?)
  • Evidence of original scientific or scholarly research contributions in the field
  • Evidence of authorship of scholarly books or articles (in scholarly journals with international circulation) in the field – (publications?)

I’m not totally sure of the difference between the last two since you can’t have publications unless you have original research. So I think you can’t have the last on its own, but if you can show that you have original research that hasn’t been published (yet?), then the one before last could be a standalone. So my guess is that if you have publications, you have already met the last two. Anyway, in my case, I think I met all except for the association membership criterion, although I may have been somewhat thin on the first (since my awards are mainly local).

This was the timeline from filing to approval:

11 April 2012: Filed I-140 under Premium Processing

13th April: USCIS received application – 2 days

16th April: I-140 approved (what a surprise..approved in 3 days!) – 5 days

30th April: I-485 filed – 19 days

19th May: Received EAD-AP combo card in the mail – 38 days

20th June: Had biometrics done – 60 days

20th July: I-485 approved for me; RFE for wife – 90 days

26th July: Permanent resident card arrived in mail – 96 days

10th August: Response for RFE filed

15th August: RFE accepted. Card ordered.

20th August: Card received

The RFE was a bit silly since we had submitted these documents already. Turns out it’s pretty common for the spouse to get an RFE. This is what we had:

  1. Please submit a copy of your official birth certificate. If the document is not in English, please include a certified English translation. If a birth certificate does not exist or cannot be obtained, you must demonstrate this and submit secondary evidence pertinent to the facts at issue.
  2. Submit a copy of the biographical page of your passport.

The Fragomen lawyers handled the entire process and it all took roughly 3 months from I-140 filing to I-485 approval. I was pleasantly surprised by the whole process although gathering the documents and all was a pain!  The lawyers + their team was top notch and made the whole process very smooth. Once USCIS made a mistake in my country of citizenship and even before I pointed this out, they had proactively taken steps to address this. On another occasion, they took care of a translation that was required – when the translation was done, there had been a spelling error and they had already gone back to the translator to fix the error. No idea if they handle individual cases, or what the charges are, but if anyone’s looking for a good lawyer/law firm, I can highly recommend these guys.

Note: Post is backdated since I don’t want this to be the first post in the blog

Posted in Personal | Tagged , , , , , , | 1 Comment

Connecting to SQL Server from Java

Almost every time I try to connect to SQL Server from Java I end up hacking something together, like copy-pasting the connection string from an old project; then again, more often than not I end up getting some sort of error and spending quite sometime Googling. So I spent sometime trying to understand the different options and thought I’d put together a few things I have learnt. I’m using eclipse, so the examples are based on that, but I’m sure you could easily find the equivalent if you’re using a different editor.

There seem to be primarily two ways to connect to SQL Server – using Windows Authentication or SQL Authentication (with a username/password). Also, we have two commonly used JDBC Type IV driversMS-JDBC and jTDS. This gives us four combinations and here are the connection strings/settings you need to get things up and running (you may need to adjust the string according to your PC name, SQL Server instance and DB name):

  1. Windows authentication + JDBC
This is the connection string we have to use:
String url ="jdbc:sqlserver://MYPC\\SQLEXPRESS;databaseName=MYDB;integratedSecurity=true";
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection conn = DriverManager.getConnection(url);

For this to work, you’ll need to have sqljdbc driver included in the build path:
image
Note that you need to point to the sqljdbc4.jar (shown below) in ‘Microsoft JDBC Driver 4.0 for SQL Server’ folder. Make sure you have all other files that go along with it as well as simply having only the .jar won’t do.
image
You would think this would be enough, but if you just run it now you’re going to get the following error:

Jan 22, 2012 1:41:43 PM com.microsoft.sqlserver.jdbc.AuthenticationJNI <clinit>
WARNING: Failed to load the sqljdbc_auth.dll cause :- no sqljdbc_auth in java.library.path

So you also need to add the path to sqljdbc_auth.dll as a VM argument:
image
Now at one stage I was having the 3.0 JDBC driver and was getting the same error above and after wasting a decent amount of time found out that SQL Server 2012 requires the JDBC 4.0 driver. So if you are working with SQL Server 2008 you might need 3.0, although I’m guessing 4.0 should be backward compatible.

2.  SQL authentication + JDBC

This is probably the easiest scenario. You need to add sqljdbc4.jar similar to (1), but don’t need the VM arguments. The connection string to use in this case is:

String userName ="username";
String password ="password";

String url ="jdbc:sqlserver://MYPC\\SQLEXPRESS;databaseName=MYDB";

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection conn = DriverManager.getConnection(url, userName, password);

Some details related to setting up a new user can be found here.

3.  Windows authentication + jTDS

jTDS uses Windows authentication by default, so this is the connection string we need to use (don’t need to explicitly mention ‘integrated security’).

String url ="jdbc:jtds:sqlserver://MYPC/MYDB;instance=SQLEXPRESS";
Class.forName("net.sourceforge.jtds.jdbc.Driver");
Connection conn = DriverManager.getConnection(url);

You also need jtds.jar in the Java build path:
image
Now at this point if you just run it you are going to get the following error:
java.sql.SQLException: I/O Error: SSO Failed: Native SSPI library not loaded. Check the java.library.path system property.
Took me a while to figure out how to resolve this, but what you need to do is something a bit similar to (1). Simply have the following as a VM argument:
image

’Path’ above is where your SSO folder is after installing the jTDS driver. Seems like for Windows authentication to work, Java needs to know where this ntlmaauth.dll is.

image

4.  SQL authentication + jTDS

Very similar to case (2). No VM arguments needed, but still need jtds.jar in the build path. Connection string to use is:

String userName ="username";
String password ="password";
String url ="jdbc:jtds:sqlserver://MYPC/MYDB;instance=SQLEXPRESS";
Class.forName("net.sourceforge.jtds.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, userName, password);

Once you have the Connection, you can run a query/stored procedure as follows:
Query/UDF
try{           

    PreparedStatement ps = conn.prepareStatement("select * from yourTable/UDF/query");
    /* if UDF, and need to pass params, can do something like:
    ...prepareStatement("select * from UDF('" + UDFinputVal + "')" */

    ResultSet rs = ps.executeQuery();

    while (rs.next()) {

        String relatedConcept = rs.getString(1);
        int shortestDistance = rs.getInt(2);
        float weightedDistance = rs.getFloat(3);

        // do stuff    }  

    rs.close();
    ps.close();            
}
catch (Exception e) {
    e.printStackTrace();
}

Stored procedure
try{           

    // execute SP that requires two string arguments    PreparedStatement ps = conn.prepareStatement("exec storedProcedure ?,?");
    ps.setEscapeProcessing(true);

    ps.setString(1, "str1");
    ps.setString(2, "str2");

    ResultSet rs = ps.executeQuery();

    while (rs.next()) {
        String strVal = rs.getString(1);
        // do stuff    }

    /* If you get multiple results back from you SP, you can iterate through them using:

    ps.getMoreResults();
    rs = ps.getResultSet();

    while (rs.next()) {
        String strVal = rs.getString(1);
        ... 
    }  */

    rs.close();
    ps.close();            
}
catch (Exception e) {
    e.printStackTrace();
}

Keywords: com.microsoft.sqlserver.jdbc.AuthenticationJNI, connecting to SQL Server from Java, eclipse connect to SQL Server, Failed to load the sqljdbc_auth.dll cause :- no sqljdbc_auth in java.library.path, java.sql.SQLException: I/O Error: SSO Failed: Native SSPI library not loaded. Check the java.library.path system property, jdbc, jtds, SQL Server Windows authentication, executing SQL Server stored procedure from Java, calling SQL Server user-defined-function (UDF) from Java, SQL Server multiple tables ResultSets

Posted in General | Tagged , , , , , , , , , , , , | 90 Comments

Singapore Airlines KrisFlyer Vs. United Airlines MileagePlus

Well, I don’t usually write much for my ‘personal’ category, but the frustration with KrisFlyer has been so high that I thought the topic would be a good one to write something about. Perhaps others with similar experience could share theirs?

I had high regard for Singapore Airlines back in the days. They were known for providing good inflight service and while in NZ, more often than not, I used to pay a bit more to fly SQ (typically ~NZD100-200) compared to Thai/Malaysian Airlines when flying to Colombo. I have been a long time loyal/devoted KrisFlyer member since ~2005 (not long enough compared to some..but still) and was an Elite Gold Member for a year, and Elite Silver Member for a couple of years (just short of making it to Gold) as well. Over the past I have been accruing miles, almost a 100% through flying, but had never tried to redeem anything to-date. My miles expired a few times, but I wasn’t planning to go anywhere. I usually delete most of the emails and whatever statements I have left show I had at least 16,000+ miles expired in the past. E.g.,

image image

I currently have ~94,000 miles and ~26,000 miles are expiring at end of August 2012 (7k in July, and 19k in August), so I’ve been looking at how to redeem some of them. We (my wife and I) are planning to go to Sri Lanka this year, so I was hoping I could get a return ticket for at least 1 person using my KF miles. Here are a number of issues/frustrations I have encountered when trying to book an award ticket using KF miles (compared to United):

1. No easy way of knowing on what dates award tickets are available
2. Extremely high fuel surcharge
3. Premier benefits
4. Baggage allowance
5. Extremely poor flexibility of points
6. Difficult/impossible to book an award ticket (with more than 1 stop or long layover?)
7. Horrible user interaction
8. Buggy user interface
9. Poor segment aggregation
10. Mileage expiration policy

Sorry for the long narrative, but if you don’t want to read it all, you can jump to My Case to see why I’m not a happy KF customer!

1. No easy way of knowing on what dates award tickets are available

SQ booking system is decent if you are trying to book a paid ticket since you can do a +/-3 day search and get a grid with prices as shown below:

image

However, if you are trying to book using KF miles, there’s no way to do this! You have to literally enter the various combinations and find out what’s available and what’s not. I see no reason why SQ can’t implement this feature in the website. Perhaps they can show the same grid as above, but show miles instead?

On the other hand, if I go to United, this is what I see for award tickets where I can quickly see when the cheapest fares are available:

image

Most importantly, on the United website, you can actually book award travel on partner airlines (i.e., Star Alliance carriers). On the other hand, the only way to book partner airline travel with KF miles is by calling their Call Centre. This is a painful process, especially when there are no seats available on the dates you want to travel. You have to keep asking them for various dates, alternative routes as well as transit times etc. You might look online for what’s available, and then call the Call Centre only to find out that there no ‘award tickets’ available on that flight. You can imagine how convenient it is when you can at least check for availability yourself (and ideally, also do the booking online).

2. Extremely high fuel surcharge:

This is probably the most frustrating/annoying issue, which has been raised by others previously (e.g., Why are Singapore Airlines Award Redemption Taxes/Charges so HIGH?, Airline Fuel and Insurance Surcharge; Kris Flyer: You need lots of miles to fly a little way). For instance, here are three specific examples:

a) JFK-SIN Return

Using the user-friendly UA booking interface, I see the following:

imageimage

Then I can go ahead and make the booking if needed:

imageimage

Total price: 65,000 miles + USD 42.10

On the other hand, if I go to SQ and try the same ticket (note that I have picked exactly the same flights), I get the following:

imageimage

As you can see, tickets are available, but I just can’t book it since the ‘buggy’ (covered later) SQ booking system says I haven’t selected all segments although I have. Very annoying!image

So just to get an idea of how many miles I need and associated costs, I did a one way search for the same two flights:

imageimage

So on SQ:
Total price: 63,750 miles + USD 688.35 (vs 65,000 miles + USD 42.10 on UA)

Amazingly, this is flying on Singapore Airlines flights (note SQ25 and SQ26)! You would think using miles on a different airline would be more expensive eh. Singapore Airlines can’t give a decent deal to their own KF members flying on their own airline!

b) AKL-CMB Return

One may argue that JFK is a US destination and SQ is primarily an Asian airline. Not sure about the validity of the argument, so just for the sake of it, I compared flying from Auckland to Colombo.

Using Mileage Plus, this is what we have:

imageimage

Using KF:

image

image

Roughly the same number of miles needed, but look at the price difference!

59,500 miles + USD 546.94 (vs 60,000 miles + USD 65.50 on UA)

c) JFK-DXB Return

I wanted to see if I could get a return ticket to Dubai from JFK so that I could at least get half-way using the KF points. This is what the customer service representative gave me:

image

Then she said total cost would be 75,000 points + SGD 937.30 (~USD 740.47).

Now, if we go to United, and try to get a return ticket from JFK to DXB for same dates, this is what we get:

imageimage

Note that the above is with a much shorter transit time as well. I just tried looking at the same itinerary SQ gave me in UA – I couldn’t find the Swiss connection back to JFK, but managed to find the same LH connection out of JFK:

imageimage

I don’t think I need to say anything here since the choice is not a hard one. It’s:

75,000 points + USD 740.47 with KF vs. 80,000 miles + USD 74.40 with MP.

Table below shows the summary for the three specific examples I’ve used (thanks for summarizing this Lifehack!):

Roundtrip
Program
Miles
Fees (USD)
Singapore – New York
Krisflyer
63,750
688.35
Mileage Plus
65,000
42.10
Auckland – Colombo
Krisflyer
59,500
546.94
Mileage Plus
60,000
65.50
New York – Dubai
Krisflyer
75,000
740.47
Mileage Plus
80,000
74.40

3. Premier benefits:

Several others have already talked about this (just Google KrisFlyer vs MileagePlus), and I haven’t really done a good enough comparison/thorough analysis where these benefits are concerned, but here are some of my observations:

a) MP is pretty good in terms of giving at least 100% award miles for almost all booking classes:

clip_image001

Compare this with KF’s:

clip_image002

So if you generally go for the cheapest Economy option, you may not always get KF miles. I remember back in the days when I used to book flights from Auckland to Colombo, the KF eligible booking class tickets were exactly NZD100 more expensive than the non-eligible one.

b) Complementary upgrades: I must have flown SQ so many times, but never ever did I get a single free upgrade. As a KF Gold, I once flew Economy from LAX-IAD on United and both my wife and I were freely upgraded to Premium-Economy. For all fairness, this was a domestic flight whereas most of SQ flights are international. MP Gold members perhaps don’t get free upgrades on international travel, in which case this point is not so valid, although in several forums I have read that KF is pretty ‘stingy’ in terms of free upgrades.

c) Other Elite benefits:

Compare the following benefits for MP Elite members flying on United:

clip_image003clip_image004clip_image005clip_image006clip_image007

with the equivalent for KF Elite members flying Singapore Airlines:

clip_image008clip_image009clip_image010clip_image011

Again, one may argue that United has many domestic flights whereas SQ has mainly international, but I’m sure SQ can afford to at least give 50% bonus miles to the Gold members?

4. Baggage Allowance:

This is not really KF or MP related, but on SQ, there is a 20kg per bag limit:

clip_image012

On United flights, this is 23kg per bag.

clip_image013

This is a 3kg difference, but if you have status, then it’s a different story since on United, you get two extra 32kg bags vs just one 23kg bag on SQ. So effectively, if you are a Star Gold and flying United, you get 56kgs extra! (32kg x 3 – 20kg x 2). This extra amount is more than double of what you get flying SQ.

clip_image014

5. Extremely poor flexibility of points:

This is a real frustration with KrisFlyer! If you look at MP, you see a whole bunch of ways to make use of your points other than booking air travel or upgrades – see http://www.united.com/web/en-US/content/mileageplus/awards/default.aspx for a list of possibilities. Now in all fairness, United is a US based airline, so one could argue that it would be a lot easier to administer a program within the same country. US is so many times bigger than Singapore, so United can partner with so many different vendors to offer a variety of ways to use miles. Fine, I can live with that limitation of KrisFlyer, but what really annoys me is that there is no way to share miles! Now there should be no excuse for this. If a family is travelling for instance, all of them could be KrisFlyer members, but it’ll often be difficult for each member to travel enough to actually make use of the points before they expire. On the other hand, if all family members could combine their points, perhaps they could get at least one award ticket. You can do this with MP (for a fee..but still it’s an option!), but with KrisFlyer the best you can do is ‘nominate’ someone.

6.  Difficult/impossible to book an award ticket (with more than 1 stop or long layover?):

If I’m paying in full for instance, I can see a number of flights from JFK-CMB. As you can see, there are plenty of seats available for early Sep departure and early Oct return.

image

When I click on one, all segments are available as well, starting from ‘sweet deals’.

image

image

However, if I click ‘KrisFlyer redemption’, I don’t get anything back:

image

image

I have tried all sorts of different dates, and it’s always been the same result. Just to prove the point, I selected the last possible dates, that is, 350 days away from now to get the same ‘no flights available’ screen.

image

I believe SQ doesn’t show the route for award tickets if there are more than two stops or a long layover, but that’s only a guess.

No such problems with MileagePlus, which happily found me a multiple routes from JFK-CMB for same dates. There were much shorter options, but here is the direct comparison flying SQ:

imageimage

According to others, “one stopover is allowed on a roundtrip saver award, though none are allowed on a one-way saver award” on SQ, so may be this is the reason I was having trouble booking the above award tickets. This may be so, but still I don’t find it a good enough excuse as a customer to not be able to book the ticket I want.

7.  Horrible user interaction:

I can’t believe how bad the SQ booking system is for a top airliner. It was so not user-friendly, but at least after the recent (July 2012) upgrade I was hoping they would improve on the usability, but doesn’t look like there were any improvements. A number of others have documented/complained about this before (there’s a whole thread devoted to website issues here) and here are some of my observations.

If I do a JFK-SIN search for instance, I end up on the following page:

image

Now if I hit ‘Change details’ and update the From and To fields as follows:

image

and then decide to look at ‘KrisFlyer redemption’, the ‘From’ field automatically gets updated to what it was before!

image

So I have to type CMB into the ‘From’ field again and press ‘Update results’:

image

I end up in the homepage with an update ‘To’ field as shown below:

image

Looks like the site ‘remembers’ the previous successful selection, or the very first selection you entered from the homepage, and somehow displays those when the system can’t find seats for the most recent from/to selection. These are suppose to be commercial websites, and I’m sure they are paying top dollars as well to whoever designs these websites. On top of all the initial development effort, don’t they do any sort of user acceptance/interaction type testing before releasing a website to the public? Turns out Singapore Airlines said sorry for dodgy site back in July 14th 2011, so I can only imagine that this was worse back then (I recall running into some issues last year after the new site was launched, but wasn’t actively trying to book travel, so can’t comment on anything specific).

8. Buggy user interface:

Somewhat related to the previous point, but at least the previous one was not a deal breaker, rather a big time inconvenience. The following I bet is an actual bug!

So I did a JFK-SIN one way search (previous was JFK-CMB with 2 stops) using KF redemption and landed on the following page:

image

As you can see, I have selected the respective flights for both segments and now when I click ‘Continue’, I get the following error:

image

So basically there’s no way to make this booking using the website although it is a pretty simple one-way flight.

9.  Poor segment aggregation:

If I search JFK to SIN using KF redemption, I get the following:

image

and then if I do SIN-CMB, I get the following:

image

Logically, you would think that now if you do a JFK-CMB for the 16th, you would get the above two combined. However, the following is what you end up with:

image

I mentioned this when I called SQ, and the agent was saying that this is because SQ doesn’t allow to book flights when there’s a long transit (or something to that effect). I explained to her how that decision needs to be left to the customer and not made by the ‘system’. It makes no sense at all to show the individual segments as ‘available’ but not allow a customer to book it if they don’t mind the long transit. Anyway, finally I managed to put some sense into the agent and she said she would call me back. Upon returning my call, she said they could make the booking for me and also give me the 15% discount for online redemption, so I’m guessing this is indeed a bug, which hopefully will get fixed at some point. Cost for this is:

44,625 points + sg671 (~US$530)

10.  Mileage expiration policy:

KF miles expire in 3 years from the date you acquired them – for instance, if you got 10k miles on 1st May 2010, and another 15k on 1 Oct 2010, 10k miles will expire on 1st May 2013 and 15k miles will expire on 1 Oct 2013 (you can extend miles for another year if you are Silver or higher). On the other hand with MP, you can literally have no expiration since all miles get updated to (activity date+18 months) every time there is some activity in the MP account. I’d imagine it’s not hard to have some sort of activity (e.g., hotel stay) once every 18 months. If you are in the US, it’s actually pretty easy to find some way to have some activity on the MP account without flying.

My Case:

Right now I’m sitting on almost 94,000 KF miles:

image

and I have no idea what to do with them. I have tried so many different routes on various partner airlines like JFK->SIN->CMB; JFK->Dubai->CMB; JFK->FRA->SIN->CMB; JFK->Doha->CMB; JFK->AUH->CMB; Basically I’ve been trying to get an award one-way ticket, and then just buy a one-way ticket for the return, or vice-versa. Alternatively, I have been trying to get a return ticket to half-way, like to Doha, Abu Dhabi, Doha, Kuwait or somewhere from JFK and buying the other segment myself, or vice-versa, but no matter what I try, SQ customer service representative tells me ‘no seats available’, or gives me some ridiculously high ‘fuel surcharge’ like USD 900 which will end up costing me pretty much the same as buying a new ticket. Taking one of the options I’m given, I’ll basically use all my miles and spend more or less the same amount of money. If I buy a new ticket, I’ll at least accumulate some new miles!

Anyway, I realized this high fuel surcharge sometime last year, and prudently joined MileagePlus. I’m thinking of the opportunity cost however, where if I had the same amount of miles on MileagePlus, I would have had 2 great options:

Option (1): Getting a return ticket from JFK-CMB for just USD 105.70

imageimageimage

Option (2): Flying Business Class one way! I have ~20k miles in MP already, so if I had the 94k KF miles in MP, it probably would have been a sweet return business class trip all the way back! 😦

imageimageimage

Based on what I’m finding, I wonder if there is any good reason for anyone to join KF, unless they are based in Singapore, and perhaps SQ is the only airline they fly. But for the average traveller, probably flying 2-3 times a year, I’d think MP would easily be a much better choice as discussed above. This combined with MP’s expiration policy makes me kick myself for ever joining KF!

Apologies in advance if I have made any error in what I’ve said here. This was based on my own personal experience rather than a thorough analysis, so happy to take any comments/suggestions/criticism, and improve this entry.

Posted in Personal | Tagged , , , , , | 16 Comments

My University Projects

I realized recently that one of my old homepages is still around on the internet. This was my second attempt to create a homepage for myself and this was done back in 2004 when I was trying to learn DreamWeaver. I think I still updated a few pages till around 2006 or so, but most of it is nicely ‘preserved’ as it was back when I created it. Anyway, one of the pages there was a collection of my University projects during undergrad. Not sure how long GeoCities will be around for, so thought I’ll migrate that page over to here with it’s original content.


I’m sure most of you (especially my uni friends) are going to be quite surprised..but I did manage to find some soft copies of some of the uni projects we’ve had, including a few from 1st and 2nd year!! I find reading some of the old reports kind of funny now mainly ‘cos of the weird formatting I’ve got. Think the 3rd and 4th year ones look a lot better.

I’m just putting the final reports up since they pretty much explain everything about the assignment or the project. I’ve got the source code too for most of them, so just mail me or something if you need any of it.

First Year

Second Year

Third Year

Fourth Year

Work Reports


Terms of Use

This site is maintained for educational purposes only. The material presented here is not solely written by the author of the website and contains documents written by a group of students during the course of the assignment or project. These names have been appropriately referenced in the reports, and your viewing of materials posted on this site does not imply any right to reproduce, retransmit, or redisplay any of it. No text, image, or other materials on the web page may be copied, distributed, retransmitted, redisplayed, or modified without the express written consent of the author. The author makes no representation or warranties, express or implied, as to the accuracy of any of the material located in the given material, whether accessed via link, frame, or by staff or student web searching. To request permission to reproduce, modify or redisplay any information extracted from this site, send e-mail, including your name, address and a description of the purpose of your intended distribution and the information you would like to distribute. However you may print and use the above material for any noncommercial, personal, or educational purposes only, provided that you do not modify any information, and include appropriate references along with those originally included with such information. Other Internet WWW sites may freely provide hypertext or “hotlinks” to this Site if necessary.

Posted in Personal | Tagged | Leave a comment

Determining shortest distance between ontology concepts using Jena OntTools

For something I was trying to do, I wanted to determine the shortest distance between two concepts in an ontology. In some forum I was reading someone had suggested to use Jena’s findShortestPath() method. Couldn’t really find a solid example as to how this works, so here’s something that worked for me. May be there’s a better/proper way to do this, so if anyone knows how to, I’m happy to get some feedback (although I’m no longer using Jena for my work).

First of all here’s a good tutorial that explains how to set up Eclipse to work with Jena. It’s basically a Jena Hello World example.

I was working with an OWL ontology created in Protégé OWL and one of the major issues I ran into was I kept getting the following error:

WARN [main] (RDFDefaultErrorHandler.java:36) – file:///C:/Users/ProjectName/(line 741 column 35): {W102} Unqualified property attributes are not allowed. Property treated as a relative URI.

Found a few forums where others had also run into the same issue, but with no proper solution. At the same time, in some other forum someone had mentioned that Jena needed the ontology to be in RDF format, so what I did was I saved my ontology as RDF/XML:

image

and that was it!

Now that I could create the Jena model, here’s the function that I used to determine the shortest distance between two OWL Classes.

public static void FindJenaDistance() {

        // Jena implementation 

        long startTime = System.currentTimeMillis();
        
        // this file needs to be created by doing "Save As.." and "RDF/XML" for a 'normal' OWL file. Otherwise we get Jena parse errors
        String inputFileName = "C:/Users/.../data/owlfile.owl";

        String ns = "http://www.ihtsdo.org/";

        OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        InputStream in = FileManager.get().open(inputFileName);
        model.read(in, "");        
        
        System.out.format("Ontology load time: (%7.2f sec)%n%n", (System.currentTimeMillis() - startTime) / 1000.0);        

        OntClass fromSubClass = model.getOntClass("http://www.ihtsdo.org/SCT_372418009");        
        OntClass toSuperClass = model.getOntClass("http://www.ihtsdo.org/SCT_106582005");

        Path path = OntTools.findShortestPath(model, fromSubClass, toSuperClass, Filter.any);

        if (path != null){
            int superClasses = 0;
            for (Statement s: path) {
                if (s.getObject().toString().startsWith(ns)) {
                    // filter out OWL Classes
                    superClasses++;
                    System.out.println(s.getObject());
                }
            }
            System.out.println("Shortest distance from " + fromSubClass + " to " + toSuperClass + " = " + superClasses);
        }else if (fromSubClass == toSuperClass){
            System.out.println("Same node");
        }else {
            System.out.println("No path from " + fromSubClass + " to " + toSuperClass);
        }   

        System.out.format("\nProcessing time: (%7.2f sec)%n%n", (System.currentTimeMillis() - startTime) / 1000.0);

    }

Posted in General | Tagged , , , | 17 Comments