Allow you to search, faceted search, add, update, remove objects from your Amazon Cloud Search Index in C#.
Amazon CloudSearch is a AWS library created and maintain by doduck prototype
Feel free to contribute to the project using push request.
Le site doduck prototype est aussi disponible en Français.
First you need a Amazon cloud search instance and it's URL (We will call it a key) It should look like : yourDomainName-xxxxxxxxxxxxx.us-east-1.cloudsearch.amazonaws.com
This example can be used with the IMDB default index that you can select when creating your Cloud Search.
It indexes movies which implement CloudSearchDocument (just an ID):
public class Movie : CloudSearchDocument
{
public List<string> actor { get; set; }
public string director { get; set; }
public DateTime mydate { get; set; }
public string title { get; set; }
public int year { get; set; }
}
Object field starts in lowercase because THEY NEED to match the field name in your index. This needs to be improved (feel free)
var cloudSearch = new CloudSearch<Movie>("YOU_AMAZON_CLOUD_SEARCH_KEY", "2011-02-01");
var movie = new Movie { id = "fjuhewdijsdjoi", title = "simple title", year = 2012, mydate = DateTime.Now, actor = new List<string> { "good actor1", "good actor2" }, director = "martin magakian" };
cloudSearch.Add(movie);
var movie = new Movie { id = "fjuhewdijsdjoi" }
cloudSearch.Delete(movie);
movie.title = "In the skin of Amazon cloud search";
cloudSearch.Update(movie);
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars"};
var found = cloudSearch.Search(searchQuery);
var bQuery = new BooleanQuery();
var gCondition = new StringBooleanCondition("genre", "Sci-Fi");
bQuery.Conditions.Add(gCondition);
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars", Size = 25, BooleanQuery = bQuery};
var found = cloudSearch.Search(searchQuery);
var bQuery = new BooleanQuery();
var gCondition = new StringBooleanCondition("genre", "Sci-Fi");
var yCondition = new IntBooleanCondition("year");
yCondition.SetInterval(2000,2004);
bQuery.Conditions.Add(gCondition);
bQuery.Conditions.Add(yCondition);
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars", Size = 20, BooleanQuery = bQuery};
var found = cloudSearch.Search(searchQuery);
Faceted search are used to display how many result can be find in each categorie. The user is usually able to drill-down each facet.
Amazon.com use facet when searching for a book. In the left panel the user can see all search result matching is search ordered by categorie "language".
var genreFacet = new Facet { Name = "genre" };
var liFacet = new List<Facet> { genreFacet };
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars", Facets = liFacet };
var found = cloudSearch.Search(searchQuery);
var genreFacetContraint = new StringFacetConstraints();
genreFacetContraint.AddContraint("Sci-Fi");
genreFacetContraint.AddContraint("Fantasy");
var genreFacet = new Facet { Name = "genre", FacetContraint = genreFacetContraint };
var liFacet = new List<Facet> { genreFacet };
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars", Facets = liFacet};
var found = cloudSearch.Search(searchQuery);
Search for movies + number of results in the 'Sci-Fi' and 'Fantasy' categories + the number of result in the year 1950 and between 1980 and 2012 (faceted search)
var genreFacetContraint = new StringFacetConstraints();
genreFacetContraint.AddContraint("Sci-Fi");
genreFacetContraint.AddContraint("Fantasy");
var genreFacet = new Facet { Name = "genre", FacetContraint = genreFacetContraint };
var yearFacetContraint = new IntFacetContraints();
yearFacetContraint.AddFrom(1950);
yearFacetContraint.AddInterval(1980, 2012);
var yearFacet = new Facet { Name = "year", FacetContraint = yearFacetContraint };
var liFacet = new List<Facet> { genreFacet, yearFacet };
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars", Facets = liFacet};
var found = cloudSearch.Search(searchQuery);
Let put everything together now: Facet for Sci-Fi,Fantasy, in 1950, between 1980 to 2012 + search only for movies in Sci-Fi from 2000 to 2004
var cloudSearch = new CloudSearch<Movie>("YOUR_CLOUD_SEARCH_API", "2011-02-01");
//build facet
var genreFacetContraint = new StringFacetConstraints();
genreFacetContraint.AddContraint("Sci-Fi");
genreFacetContraint.AddContraint("Fantasy");
var genreFacet = new Facet { Name = "genre", FacetContraint = genreFacetContraint };
var yearFacetContraint = new IntFacetContraints();
yearFacetContraint.AddFrom(1950);
yearFacetContraint.AddInterval(1980, 2012);
var yearFacet = new Facet { Name = "year", FacetContraint = yearFacetContraint };
var liFacet = new List<Facet> { genreFacet, yearFacet };
//build boolean query
var bQuery = new BooleanQuery();
var gCondition = new StringBooleanCondition("genre", "Sci-Fi");
var yCondition = new IntBooleanCondition("year");
yCondition.SetInterval(2000,2004);
bQuery.Conditions.Add(gCondition);
bQuery.Conditions.Add(yCondition);
//build search
var searchQuery = new SearchQuery<Movie> {Keyword = "star wars", Facets = liFacet, Size = 20, BooleanQuery = bQuery};
//search
var found = cloudSearch.Search(searchQuery);
Search for movies where genre is one of: "Sci-Fi" or "Fantasy" or "other"
var list = new List<string> { "Sci-Fi", "Fantasy", "other" };
var stringList = new StringListBooleanCondition("genre", list, ConditionType.OR);
var bQuery = new BooleanQuery();
bQuery.Conditions.Add(stringList);
_searchQuery = new SearchQuery<Movie> { BooleanQuery = bQuery };
Search for movies where genre categories is in: "Sci-Fi" and "Fantasy" and "other" in the same time.
var list = new List<string> { "Sci-Fi", "Fantasy", "other" };
var stringList = new StringListBooleanCondition("genre", list, ConditionType.OR);
var bQuery = new BooleanQuery();
bQuery.Conditions.Add(stringList);
_searchQuery = new SearchQuery<Movie> { BooleanQuery = bQuery };
Note:
IntListBooleanCondition achieve the same as StringListBooleanCondition with Integer.
More complex search can be done using Grouped Condition. It's possible to search for "ConditionA" and / or "ConditionB".
Note:
maybe "StringListBooleanCondition" and "IntListBooleanCondition" are more suitable depending on the case.
The query will return all the movies who match "ConditionA" or "ConditionB" Return the movies who are in Sci-Fi or made from 2013
var conditionA = new StringBooleanCondition("genre", "Sci-Fi");
var conditionB = new IntBooleanCondition("year");
conditionB.SetFrom(2013);
var groupCondition = new GroupedCondition(conditionA, ConditionType.AND, conditionB);
var bQuery = new BooleanQuery();
bQuery.Conditions.Add(groupCondition);
_searchQuery = new SearchQuery<Movie> { BooleanQuery = bQuery };
The query will return all the movies who match "ConditionA" and "ConditionB" Return the movies who are in Sci-Fi and made from 2013
var conditionA = new StringBooleanCondition("genre", "Sci-Fi");
var conditionB = new IntBooleanCondition("year");
conditionB.SetFrom(2013);
var groupCondition = new GroupedCondition(conditionA, ConditionType.OR, conditionB);
var bQuery = new BooleanQuery();
bQuery.Conditions.Add(groupCondition);
_searchQuery = new SearchQuery<Movie> { BooleanQuery = bQuery };
The query will return all movies who match "(movies in 1990 AND genre "Sci-Fi")" OR (movies in 2013 AND genre "Fantasy")
var condition1A = new StringBooleanCondition("genre", "Sci-Fi");
var condition1B = new IntBooleanCondition("year");
condition1B.SetFrom(1990);
var groupCondition1 = new GroupedCondition(condition1A, ConditionType.AND, condition1B);
var condition2A = new StringBooleanCondition("genre", "Fantasy");
var condition2B = new IntBooleanCondition("year");
condition2B.SetFrom(2013);
var groupCondition2 = new GroupedCondition(condition2A, ConditionType.AND, condition2B);
var groupConditionAll = new GroupedCondition(groupCondition1, ConditionType.OR, groupCondition2);
var bQuery = new BooleanQuery();
bQuery.Conditions.Add(groupConditionAll);
_searchQuery = new SearchQuery<Movie> { BooleanQuery = bQuery };
Documents can be Add, Update and Delete by "pack" using batch. It use only one HTTP request to add, remove, update multiple documents.
Note:
Under the hood Amazing-Cloud-Search split the batch into 5 Mb maximum request in order to meet Amazon API requirement.
A 12Mb bash request will send 3 HTTP requests. 5Mb + 5Mb + 2Mb = 12Mb
var movie1 = new Movie { id = "fjuhewdijsdjoi", title = "movie1"};
var movie2 = new Movie { id = "sdhuslzajshdus", title = "movie2"};
var movies = new List<Movie> { movie1, movie2 };
movie1.Title = "movie1_bis";
movie2.Title = "movie2_bis";
var moviesBis = List<Movie>{ movie1, movie2 };
cloudSearch.Update(moviesBis);
var moviesToRemove = List<Movie>{ movie1, movie2 };
cloudSearch.Delete(moviesToRemove);
SearchQuery accepts parameter Size for the number of results. But also accepts a parameter Start which can by used for paginating the results. The total number of results is also displayed in the search results: found.hits.found
SearchQuery also accepts parameters for ordering the results.
All movies from the oldest to the youngest (descending):
var searchQuery = new SearchQuery<Movie> { OrderByField = "year", Order = Order.DESCENDING };
All movies from the youngest to the oldest (ascending):
var searchQuery = new SearchQuery<Movie> { OrderByField = "year", Order = Order.ASCENDING };
Without any OrderByField set, CloudSearch default ordering will be used.
You can also request the top facet as part of the results. Facet object accepts a TopResult parameter. For example we want the top 3 movie genres of our search
var genreFacet = new Facet { Name = "genre", TopResult = 2};
- Json.NET
Feel free to fork and improuve Amazing Cloud Search API.
Developed by Martin Magakian dev.martin.magakian@gmail.com
For doduck prototype (English)
Pour doduck prototype (Français)
MIT License (MIT)