How can I store Maps in POJOs in Solr? - dictionary

How can I store Maps in POJOs in Solr? Currently I have a construct like this
#Field("*_locId")
protected Map<String, Integer> geoLocationToLocationId;
In the schema.xml file:
<dynamicField name="*_locId" type="int" indexed="false" stored="true" multiValued="false" />
adding via:
public void addGeoLocationToLocationAutoInMapping(GeoCoordinates geoCoordinates,
Integer id) {
if(this.geoLocationToLocationId == null) {
this.geoLocationToLocationId = new HashMap<String, Integer>();
}
this.geoLocationToLocationId.put(geoCoordinates.toString() +
"_locId", id);
}
getting is similar.
This works, but it's kinda dirty that I store a Java Map like this in Solr because I can get loads of fields. Is there another way to write Java Maps into Solr?
I don't want to index them, I just want to save the data.

Though I would like to follow #Geert-Jan's advice in general, there are times you just want to have Solr return all the data you need. A better hack to store a simple map (String to Integer) like yours in Solr is to store the keys and values as two separate multi-valued fields and make sure the indexes agree on them. So you would have one mutli-valued field like:
geo_location: new york, los angeles, chicago
and another like
location_id: 1, 2, 3
And make sure that none of the values is null in the location_id field, else your indexes in the fields won't match.

Related

Handling reads of Cosmos DB container with multiple types?

I'd like to store several different object types in a single Cosmos DB container, as they are all logically grouped and make sense to read together by timestamp to avoid extra HTTP calls.
However, the Cosmos DB client API doesn't seem to provide an easy way of doing the reads with multiple types. The best solution I've found so far is to write your own CosmosSerializer and JsonConverter, but that feels clunky: https://thomaslevesque.com/2019/10/15/handling-type-hierarchies-in-cosmos-db-part-2/
Is there a more graceful way to read items of different types to a shared base class so I can cast them later, or do I have to take the hit?
Thanks!
The way I do this is to create the ItemQueryIterator and FeedResponse objects as dynamic and initially read them untyped so I can inspect a "type" property that tells me what type of object to deserialize into.
In this example I have a single container that contains both my customer data as well as all their sales orders. The code looks like this.
string sql = "SELECT * from c WHERE c.customerId = #customerId";
FeedIterator<dynamic> resultSet = container.GetItemQueryIterator<dynamic>(
new QueryDefinition(sql)
.WithParameter("#customerId", customerId),
requestOptions: new QueryRequestOptions
{
PartitionKey = new PartitionKey(customerId)
});
CustomerV4 customer = new CustomerV4();
List<SalesOrder> orders = new List<SalesOrder>();
while (resultSet.HasMoreResults)
{
//dynamic response. Deserialize into POCO's based upon "type" property
FeedResponse<dynamic> response = await resultSet.ReadNextAsync();
foreach (var item in response)
{
if (item.type == "customer")
{
customer = JsonConvert.DeserializeObject<CustomerV4>(item.ToString());
}
else if (item.type == "salesOrder")
{
orders.Add(JsonConvert.DeserializeObject<SalesOrder>(item.ToString()));
}
}
}
Update:
You do not have to use dynamic types if want to create a "base document" class and then derive from that. Deserialize into the documentBase class, then check the type property check which class to deserialize the payload into.
You can also extend this pattern when you evolve your data models over time with a docVersion property.

How to retrieve a property of collection as a collection of string using Java Stream api

I have a list of class Category which contains many attributes like code, name, description, supercategory, productlist, etc. Now I want to iterate over it and retrieve each category's code and store add it in list of string. This is how I am doing it with old school way. I want to know if this can be done in better, cleaner and efficient way with Java 8 Streams.
List<Category> categories = categoryService.getCategoriesForProductCode(productCode);
List<String> categoryCodes = new ArrayList<>();
if(CollectionUtils.isNotEmpty(categories)){
for(Category cat : categories){
categoryCodes.add(cat.getCode);
}
}
You can do like this
categoryCodes = categories.stream()
.map(category->catgory.getCode()) // .map(Category::getCode)
.collect(Collectors.toList());

how to retrieve java map in javascript?

I'm using JSF1.2 apache trinidad tag. I have a requirement like based on the drop down list the associated list of array values should get rendered into the UI.My Bean will have a map (drop down value as key which is unique, the associated list of values retrieved from DB) will be readily available when the page loads. In java script, how to retrieve the associated list value from this map and how to return back the array value into UI? Is there any other options available to achieve this requirement?
Your help on this is really much appreciated.
If I understand this right, you have the entire map available when the page is rendered.
You could prebuild the selectItems in the dropdown beforehand like this:
Map<String, List<String>> map;
//read the map content here
List<SelectItem> items = new ArrayList<SelectItem>();
for(String key: map.keySet()){
items.add(new SelectItem(key, map.get(key)));
}
These items will have the key as the label and the corresponding array as the value.
When you use this in your interface you can do this:
<tr:selectOneChoice value="#{bean.selectedArray}" required="true" autoSubmit="true">
<f:selectItems value="#{bean.items}"
</tr:selectOneChoice>
<tr:outputText value="#{bean.selectedArray}" />
The code isn't complete, but it should get you started.

NHibernate: adding calculated field to query results

I have inherited an ASP.NET website built on NHibernate, with which I have no experience. I need to add a calculated field based on a column in a related table to an existing query. In SQL, this would be done easily enough using a correlated subquery:
select
field1,
field2,
(select count(field3) from table2 where table2.table1ID = table1.ID) calc_field
from
table1
where
[criteria...]
Unfortunately, of course, I can't use SQL for this. So in reality, I have three related questions:
What is the best way to trace through the web of interfaces, base classes, etc used by NHibernate in order to pinpoint the object where I need to add the field?
Having located that object, what, if anything, has to be done besides adding a public property to the object corresponding to the new field?
Are there any NHibernate-specific considerations with regard to referencing a related object in a query?
Here is the existing code that performs the search:
public INHibernateQueryable<C> Search(ISearchQuery query, string sortField)
{
_session = GetSession();
var c = _session.Linq<C>();
c.Expand("IP");
c.Expand("LL");
c.Expand("LL.Address");
c.Expand("LL.Address.City");
c.Expand("LL.Address.City.State");
c.Expand("LL.Address.City.County");
c.Expand("CE");
c.Expand("IC");
c.Expand("AR");
c.Expand("ER");
c.Expand("Status");
var res = _SearchFilters
.Where(x => x.ShouldApply(query))
.Aggregate(c, (candidates, filter) => (INHibernateQueryable<C>) filter.Filter(candidates, query));
res = SortSearch(res, sortField);
return res;
}
I appreciate any advice from experienced Hibernators.
Thanks,
Mike
If you are only interested in returning a query containing a computed value, you can still call a stored procedure in NHibernate and map the results to a POCO in the same way as you map a table for CRUD operations; obviously read-only instead of updatable.
Have a look at the ISession.CreateSQLQuery method; I can post an example from one of my projects if you need one.

ASP.NET KB system / search engine

Our company has a "MyAccount" where we would like to put a knowledge base behind. We have a CRM system where the help calls are recorded and some knowledge base articles are written into the database. The master problem (same basic help call) is tagged with keyword(s). We also have CHM help files for the software we sell (some users never use the internal help system, they go online), PDF whitepapers and tutorials in a protected directory. I would like to either buy, or quickly build an ASP.NET solution where a user can search the database to display the help article and also show tutorials or whitepapers or a help file from the CHM.
Requirements: It must look like our website. I have a master page, so any content page has to pretty much be white...no graphics, colors, etc.
Does anyone know a 3rd party search engine, or an example with some source code on how to use Lucene.NET to build a search index database from an existing database?
You can build such solution with Lucene .Net.
Keep your docs in database (as already) and index with Lucene.Net docs you want.
Lucene will have its own index in file system.
You need to provide synchronization between your docs in DB and Lucene index, so when document in DB changes, you need to re-index it with Lucene.
Synchronization (matching between DB and Lucene index) can be based on some unique key value from DB (ex: ID).
So, when you want to add some document to Lucene index, you index the document content (you don't need to save content in Lucene) and 'save' it in Lucene with unique key value from DB (lets say ID).
Then you can search Lucene index and get list of matching document IDs.
And retreive them from your DB by those IDs and show to user.
Below is example method from my project, it adds document to Lucene index.
InformationAsset in method argument is the document from DB I want to index.
This method creates 'Lucene document' with few 'fields':
'field': content of the doc from db (InformationAsset from method argument)
'fieldId': it's ID of the InformationAsset from database, to match Database and Lucene index
'fieldPubDate': publication date, I can create advanced queries to Lucene engine basing on all fields.
'fieldDataSource': it's some kind of category.
public void AddToIndex(Entities.InformationAsset infAsset, IList<Keyword> additionalKeywords)
{
Analyzer analyzer = new StandardAnalyzer();
IndexWriter indexWriter = new IndexWriter(LuceneDir, analyzer, false);
Document doc = new Document();
// string z dodatkowymi slowami po ktorych ma byc tez zindeksowana tresc
string addKeysStr = "";
if(additionalKeywords != null)
{
foreach (Keyword keyword in additionalKeywords)
{
addKeysStr += " " + keyword.Value;
}
}
addKeysStr += " " + m_RootKeyword;
string contentStr;
contentStr = infAsset.Title + " " + infAsset.Content + addKeysStr;
// indeksacja pola z trescia
Field field = new Field(LuceneFieldName.Content, contentStr, Field.Store.NO, Field.Index.TOKENIZED,
Field.TermVector.YES);
// pole z Id
Field fieldId = new Field(LuceneFieldName.Id, infAsset.Id.ToString(), Field.Store.YES, Field.Index.UN_TOKENIZED);
// pole publish date
Field fieldPubDate = new Field(LuceneFieldName.PublishDate,
DateTools.DateToString(infAsset.PublishingDate, DateTools.Resolution.MINUTE),
Field.Store.YES, Field.Index.NO_NORMS, Field.TermVector.YES);
// pole DataSource
// pole z Id
Field fieldDataSource = new Field(LuceneFieldName.DataSourceId, infAsset.DataSource.Id.ToString(), Field.Store.YES,
Field.Index.UN_TOKENIZED);
doc.Add(field);
doc.Add(fieldId);
doc.Add(fieldPubDate);
doc.Add(fieldDataSource);
doc.SetBoost((float)CalculateDocBoostForInfAsset(infAsset));
indexWriter.AddDocument(doc);
indexWriter.Optimize();
indexWriter.Close();
}

Resources