Adding Preferential and Random Sorting to MapPoint Web Service Applications

 

IMPORTANT: MapPoint Web Service was retired on November 18, 2011. Please see Bing Maps for a list of current Bing Maps APIs.

Grace Qiu
Microsoft Corporation

June 2004

Applies to:
   Microsoft MapPoint Web Service, Version 3.5

Summary: Learn how to enhance your Microsoft MapPoint Web Service applications with preferential and random sorting. (8 printed pages)

Contents

Introduction
SortProperties Property
Preferential Sorting
Random Sorting
Conclusion

Introduction

With Microsoft MapPoint Web Service 3.5, you can now sort search results based on the values of specific entity properties. The new SortProperties property satisfies most locator scenarios for sorting search results. Some locator applications, however, such as an insurance agent locator or a hotel finder, require advanced sorting to give preference to particular agents or hotels. These applications may also require that a portion of the search results be presented in random order, so that no preference is given to any result.

This article first describes how to use the SortProperties property, and then illustrates how to do preferential and random sorting, using a hotel-finder application for a travel Web site as an example.

SortProperties Property

The SortProperties property contains an array of SortProperty objects that are used to sort results returned by the "find" methods: FindNearby, FindByID, FindByProperty, and FindNearRoute.

The SortProperty class has a PropertyName property, which contains the name of the property by which to order the results. The data type of the PropertyName property affects how the results are sorted. Sorting by using a String property, such as PrimaryCity, sorts the results alphabetically, and sorting by using an Int or a Double property, such as Stars (which represents a quality rating), sorts the results numerically.

The SortProperty class also has a Direction property that you can use to specify whether the results are sorted in ascending or descending order. The default is SortDirection.Ascending.

You can use a maximum of three properties to sort the search results. When you use multiple properties, the order in which they are specified determines the priority by which the search results are sorted. For example, if the order is StoreName, PrimaryCity, and Subdivision, the search results are sorted first by StoreName, then by PrimaryCity, and then by Subdivision.

Preferential Sorting

In many scenarios, you might want to give preference to locations with specific characteristics. For example, users can use our hotel-finder application to find hotels near or in the city to which they are traveling. Each hotel has a quality rating, ranging from five stars for "excellent" to one star for "poor." To give preference to hotels with a higher quality rating, the search results must be sorted first by quality and then by city name. In the final results, the five-star hotels are at the top of the list, and each group of hotels is sorted by the city name in ascending order.

This example assumes that an entity property named Stars exists in the database. The property is of type Int, with possible values ranging from 1 through 5.

The following example code defines the entity properties we'll use to sort the search results, and specifies how the results will be sorted.

[Visual Basic .NET]
Dim mySortProperties(1) As SortProperty
mySortProperties(0) = New SortProperty
mySortProperties(0).PropertyName = "Stars"
mySortProperties(0).Direction = SortDirection.Descending
mySortProperties(1) = New SortProperty
mySortProperties(1).PropertyName = "PrimaryCity"
mySortProperties(1).Direction = SortDirection.Ascending
myFindFilter.SortProperties = mySortProperties

[C#]
SortProperty[] mySortProperties = new SortProperty[2];
SortProperty mySortProperties[0] = new SortProperty();
mySortProperties[0].PropertyName = "Stars";
mySortProperties[0].Direction = SortDirection.Descending;
SortProperty mySortProperties[1] = new SortProperty();
mySortProperties[1].PropertyName = "PrimaryCity";
mySortProperties[1].Direction = SortDirection.Ascending;
myFindFilter.SortProperties = mySortProperties;

Random Sorting

Suppose that the results from the previous query contain a set of hotels of the same quality that are within the same city (and are the same distance from the specified location, if the results are from a call to the FindNearby method). These hotels are listed in the order in which they were returned from the database, possibly giving the appearance that additional preference is being given to certain hotels. To eliminate this problem, we'll apply random sorting to this set of hotels.

The following steps are required to implement random sorting:

  1. Copy the original result set to another result set. The new result set will be used to reorder the original set.
  2. Randomly generate an array of integers, between the index of where the random sorting should start, and the index of where the sorting should end (the starting index ** plus the number of records to sort).
  3. Iterate through the portion of the results to be reordered, and use the randomly generated numbers to reset the order of the records.

The following code example copies the original result set by using the CopyResults method. This example code assumes that the methods that are called by CopyResultsCopyAddress, CopyEntity, and CopyBestMapView—are already defined elsewhere.

[Visual Basic .NET]
Dim copyFindResults As New FindResults()
copyFindResults.NumberFound = originalFindResults.NumberFound
copyFindResults.Results = CopyResults(originalFindResults.Results)
copyFindResults.StartIndex = originalFindResults.StartIndex
copyFindResults.TopScore = originalFindResults.TopScore

Public Shared Function CopyResults(originalResults() As FindResult) _
As FindResult()
   Dim resultsSetCopy(originalResults.Length) As FindResult
   Dim i As Integer
   For i = 0 To originalResults.Length - 1
      resultsSetCopy(i) = New FindResult()
      resultsSetCopy(i).Score = originalResults(i).Score
      resultsSetCopy(i).FoundLocation = New Location()
      
      'The CopyAddress method copies all properties of
'originalResults[i].FoundLocation.Address to 
'resultSetCopy[i].FoundLocation.Address.
      resultsSetCopy(i).FoundLocation.Address = _
CopyAddress(originalResults(i).FoundLocation.Address)
      resultsSetCopy(i).FoundLocation.LatLong.Latitude = _
originalResults(i).FoundLocation.LatLong.Latitude
      resultsSetCopy(i).FoundLocation.LatLong.Longitude = _
originalResults(i).FoundLocation.LatLong.Longitude
      'The CopyBestMapView method copies all properties of 
'originalResults[i].FoundLocation.BestMapView to 
'resultSetCopy[i].FoundLocation.BestMapView.
      If Not (originalResults(i).FoundLocation.BestMapView Is Nothing) Then
         resultSetCopy(i).FoundLocation.BestMapView = _
CopyBestMapView(originalResults(i).FoundLocation.BestMapView)
      End If
      resultSetCopy(i).FoundLocation.DataSourceName = _
originalResults(i).FoundLocation.DataSourceName
      'The CopyEntity method copies all properties of 
'originalResults[i].FoundLocation.Entity to 
'resultSetCopy[i].FoundLocation.Entity.
      resultSetCopy(i).FoundLocation.Entity = _
CopyEntity(originalResults(i).FoundLocation.Entity)
   Next i
   Return resultsSetCopy
End Function 'CopyResults

[C#]
FindResults copyFindResults = new FindResults();
copyFindResults.NumberFound = originalFindResults.NumberFound; 
copyFindResults.Results = CopyResults(originalFindResults.Results); 
copyFindResults.StartIndex = originalFindResults.StartIndex; 
copyFindResults.TopScore = originalFindResults.TopScore;
public static FindResult[] CopyResults(FindResult[] originalResults) 
{
    FindResult[] resultsSetCopy = new FindResult[originalResults.Length]; 
    for(int i=0; i<originalResults.Length; i++)
   {
   resultsSetCopy[i] = new FindResult();
   resultsSetCopy[i].Score = originalResults[i].Score; 
   resultsSetCopy[i].FoundLocation = new Location();

   //CopyAddress copies all properties of 
//originalResults[i].FoundLocation.Address to 
//resultSetCopy[i].FoundLocation.Address. 
   resultsSetCopy[i].FoundLocation.Address = 
CopyAddress(originalResults[i].FoundLocation.Address); 
   resultsSetCopy[i].FoundLocation.LatLong.Latitude = 
originalResults[i].FoundLocation.LatLong.Latitude;
   resultsSetCopy[i].FoundLocation.LatLong.Longitude = 
originalResults[i].FoundLocation.LatLong.Longitude;
   //The CopyBestMapView method copies all properties of
//originalResults[i].FoundLocation.BestMapView to 
//resultSetCopy[i].FoundLocation.BestMapView.
   if(originalResults[i].FoundLocation.BestMapView!=null)
      resultSetCopy[i].FoundLocation.BestMapView = 
CopyBestMapView(originalResults[i].FoundLocation.BestMapView);
   resultSetCopy[i].FoundLocation.DataSourceName = 
originalResults[i].FoundLocation.DataSourceName;
   //The CopyEntity method copies all properties of 
//originalResults[i].FoundLocation.Entity to 
//resultSetCopy[i].FoundLocation.Entity.
   resultSetCopy[i].FoundLocation.Entity = 
CopyEntity(originalResults[i].FoundLocation.Entity);
   }
    return resultsSetCopy; 
}

Next, we'll randomly generate an array of integers between the index of where the random sorting should start (startIndex) and the index of where the sorting should end (startIndex plus the number of records to sort).

[Visual Basic .NET]
'The count variable specifies number of records to sort.
Dim endIndex As Integer = startIndex + count
'If startIndex is 0, add 1 0+count=count.
Dim min As Integer = startIndex
Dim max As Integer = endIndex
'If startIndex is 0, generate numbers between 1 to 1 + count.
If startIndex = 0 Then
   min += 1
   max += 1
End If
'The num variable is used to store the generated number.
Dim num As Integer
'The randomNum array is used to keep track of the random numbers.
Dim randomNum(count) As Integer
'The duplicate variable is Boolean and is used to keep track of whether 
'the generated number is a duplicate. If the number is a duplicate, 
'generate another number, else store the number. 
Dim duplicate As Boolean = True
'Create an array of random numbers.
Dim a As Integer
For a = 0 To count - 1
   'While a new random number is not found, continue to generate new 
'random number.
   While duplicate
      Dim R As New Random()
      num = R.Next(min, max)
      randomNum(a) = num
      duplicate = False
      If a > 0 Then
         'Check for duplicate random numbers.
         Dim b As Integer
         For b = 0 To a - 1
            If num = randomNum(b) Then
               duplicate = True
               Exit For
            End If
         Next b 'End of for loop b.
      End If 'End of if a > 0.
   End While 'End of while duplicate=true.
   duplicate = True 'reset "duplicate" for the next while loop
Next a

[C#]
//The count variable specifies number of records to sort.
int endIndex = startIndex+count;
//If startIndex is 0, add 1 0+count=count.
int min = startIndex;
int max=endIndex;
//If startIndex is 0, generate numbers between 1 to 1 + count. 
if (startIndex == 0) 
{
min += 1;
max += 1; 
}
//The num variable is used to store the generated number.
int num;
//The randomNum array is used to keep track of the random numbers.
int[] randomNum = new int[count];
//The duplicate variable is Boolean and is used to keep track of 
//whether the generated number is a duplicate. If the number is a 
//duplicate, generate another number, else store the number. 
bool duplicate=true;
//Create an array of random numbers.
for (int a =0; a <count; a++)
{
//While a new random number is not found, continue to generate new 
//random number.
while (duplicate)
{
Random R =new Random();
num = R.Next(min,max);
randomNum[a] = num;
duplicate = false;
if (a > 0)
{
//Check for duplicate random numbers.
for (int b=0; b<a; b++)
{
if (num == randomNum[b])
{
duplicate=true;
break;
}
}//End of for loop b.
}//End of if a > 0.
}//End of while duplicate=true.
duplicate = true; //reset "duplicate" for the next while loop
}

Finally, we'll iterate through the results from startIndex to startIndex ** plus count, and use the randomly generated numbers to reset the order of the records between startIndex and startIndex plus num.

[Visual Basic .NET]
'The c variable is used as an index counter for the randomNum array.
Dim c As Integer = 0 
Dim i As Integer
For i = startIndex To endIndex - 1
   num = randomNum(c)
   If startIndex = 0 Then
'subtract the "1" added at the beginning for generating random numbers
      num -= 1
   End If
   originalFindResults.Results(i) = copyFindResults.Results(num)
Next I

[C#]
int c=0;//index counter for the randomNum array
for (int i=startIndex; i < endIndex; i++)
{
num = randomNum[c]; 
//Subtract the "1" added at the beginning for generating random numbers.
if (startIndex==0) num -= 1; 
originalFindResults.Results[i] = copyFindResults.Results[num];
++c; 
}

Conclusion

By using the SortProperties property of MapPoint Web Service, you can sort search results by the values of up to three entity properties. You can use SortProperties to perform preferential sorting, and move preferred agents, stores, or hotels to the top of the list of search results. Additionally, you can add random sorting to your locator application if you need to ensure that no preference is given to particular results.

 

About the author

Grace Qiu is a Web Development Engineer in the Microsoft MapPoint Business Unit and is a member of the Professional Services team.