I'm doing an assignment where I have to search through keys in a TreeMap (that are mapped to files that they are found in. Basically, this TreeMap is an Inverted Index) that start with a query word that we specify to the program in a query file. However, for efficiency purposes, my professor does not want is to iterate through ALL the keys in the TreeMap when we look for keys that start with the query words, rather she wants us to iterate through only the keys that we need to iterate through. For example, if the query word starts with C, then we should only iterate through the keys that start with C. Any ideas on how to approach this?
Use the TreeMap's subMap() method to obtain a SortedMap that contains only the range of keys that you want to examine. Then iterate over that SortedMap.
Here is the basic implementation of what #ottomeister suggested:
public class Tester{
public static void main(String a[]){
TreeMap<CustomObject,String> tm = new TreeMap<CustomObject,String>();
tm.put(new CustomObject(4,"abc"),"abc");
tm.put(new CustomObject(7,"bcd"),"bcd");
tm.put(new CustomObject(25,"cde"),"cde");
tm.put(new CustomObject(18,"def"),"def");
tm.put(new CustomObject(2,"efg"),"efg");
tm.put(new CustomObject(8,"fgh"),"fgh");
tm.put(new CustomObject(3,"aab"),"aab");
tm.put(new CustomObject(13,"aab"),"abb");
Map<CustomObject, String> sub = tm.subMap(new CustomObject(9,""),new CustomObject(20,""));
for(Map.Entry<CustomObject,String> entry : sub.entrySet()) {
CustomObject key = entry.getKey();
String value = entry.getValue();
System.out.println(key.getId() + " => " + value);
}
}
}
class CustomObject implements Comparable<CustomObject>{
private int id;
private String Name;
CustomObject(int id, String Name){
this.id = id;
this.Name = Name;
}
#Override
public int compareTo(#NotNull CustomObject o) {
return this.id - o.id;
}
public int getId(){
return this.id;
}
}
output:
13 => abb
18 => def
Related
Using the Jackson Hash Mapper with Flatten=true my Date fields are getting discarded. Is this the correct behaviour or a bug? Is there a way to have Date serialized with Flatten=true?
I've used the following test Pojo:
import java.util.Date;
public class FooClass{
private Boolean foolean;
private Integer barteger;
private String simpleString;
private Date myDate;
public void setFoolean(Boolean value){ foolean = value; }
public Boolean getFoolean(){ return foolean; }
public void setBarteger(Integer value){ barteger = value; }
public Integer getBarteger(){ return barteger; }
public void setSimpleString(String value) { simpleString = value; }
public String getSimpleString(){ return simpleString; }
public void setMyDate(Date value) { myDate = value; }
public Date getMyDate(){ return myDate; }
}
public class Main {
public static void main(String[] args) throws ParseException,
JsonParseException, JsonMappingException, IOException {
Jackson2HashMapper hashMapper = new Jackson2HashMapper(true);
FooClass fooObject = new FooClass();
fooObject.setFoolean(true);
fooObject.setBarteger(10);
fooObject.setSimpleString("Foobar");
fooObject.setMyDate(new Date());
Map<String, Object> hash = hashMapper.toHash(fooObject);
for (String key: hash.keySet())
{
System.out.println("hash contains: " + key + "=" +
hash.get(key.toString()));
}
FooClass newFoo = (FooClass)(hashMapper.fromHash(hash));
System.out.println("FromHash: " + newFoo);
}
}
In this case I get the following output:
hash contains: #class=FooClass
hash contains: foolean=true
hash contains: barteger=10
hash contains: simpleString=Foobar
FromHash: FooClass#117159c0
If I change new Jackson2HashMapper(false); then I get:
hash contains: #class=FooClass
hash contains: foolean=true
hash contains: barteger=10
hash contains: simpleString=Foobar
hash contains: myDate=[java.util.Date, 1547033077869]
FromHash: FooClass#7ed7259e
I was expecting to get the Date field serialized in both cases - perhaps with an additional field describing the date type (flattened).
I traced the reason for this to the following line in the HashMapper code:
typingMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
Where the mapper is configured.
It seems to issue in Jackson2HashMapper.
After digging into the source of Jackson2HashMapper, it seems to issue in Jackson2HashMapper.
created an issue for this, DATAREDIS-1001
Jackson2HashMapper does not serialize Date/Calender fields when flatten = true
Document structure is:
db.lookupdata.insert({ parent_key : "category" , key : "accessories" , value : ["belts","cases","gloves","hair","hats","scarves","sunglasses","ties","wallets","watches"]})
i want to store array filed values in java array list
i am finding the document like this:
FindIterable<Document> iterable1 = docCollectionLookup.find(Filters.eq("parent_key", "category"));
Iterator<Document> iter1=iterable1.iterator();
while(iter1.hasNext())
{
Document theObj = iter1.next();
categotyLookUpMap.put(theObj.getString("key"), list);
}
now here how can i retrieve array field values(key:"value") in ArrayList
You can retrieve array field values(key:"value") in ArrayList just like how you retrieve string field key. Please refer below:
FindIterable<Document> iterable1 = docCollectionLookup.find(Filters.eq("parent_key", "category"));
Iterator<Document> iter1=iterable1.iterator();
//Create a HashMap variable with type <String,ArrayList>,according to your needs
Map<String,ArrayList> categotyLookUpMap = new HashMap<String,ArrayList>();
while(iter1.hasNext())
{
Document theObj = iter1.next();
//Get method of Document class will return object,parse it to ArrayList
categotyLookUpMap.put(theObj.getString("key"), (ArrayList)theObj.get("value"));
}
Alternatively, you can use Morphia which is MongoDB object-document mapper in Java. You can setup dependency / download JAR from here
First, create LookupData class to map to lookupdata collection. Annotation #Id is required else will throw exception with message "No field is annotated with #Id; but it is required". So create an _id field for it.
#Entity("lookupdata")
public class LookupData {
#Id
String _id ;
#Property("parent_key")
String parentKey;
String key;
ArrayList<String> value;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getParentKey() {
return parentKey;
}
public void setParentKey(String parentKey) {
this.parentKey = parentKey;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public void setValue(ArrayList<String> value) {
this.value = value;
}
public ArrayList<String> getValue() {
return value;
}
}
Retrieve array field values as below:
MongoClient mongoClient = new MongoClient(new MongoClientURI("mongodb://localhost"));
Morphia morphia = new Morphia();
morphia.map(LookupData.class);
//lookupdata collection is under my local db "tutorials" in this case
Datastore datastore = morphia.createDatastore(mongoClient, "tutorials");
Map<String,ArrayList> categotyLookUpMap = new HashMap<String,ArrayList>();
LookupData lookupData = datastore.find(LookupData.class).get();
categotyLookUpMap.put(lookupData.getKey(), lookupData.getValue());
I have reviewed multiple examples for how to construct a TreeTable from from a Container datasource and just adding items iterating over an Object[][]. Still I'm stuck for my use case.
I have a bean like so...
public class DSRUpdateHourlyDTO implements UniquelyKeyed<AssetOwnedHourlyLocatableId>, Serializable
{
private static final long serialVersionUID = 1L;
private final AssetOwnedHourlyLocatableId id = new AssetOwnedHourlyLocatableId();
private String commitStatus;
private BigDecimal economicMax;
private BigDecimal economicMin;
public void setCommitStatus(String commitStatus) { this.commitStatus = commitStatus; }
public void setEconomicMax(BigDecimal economicMax) { this.economicMax = economicMax; }
public void setEconomicMin(BigDecimal economicMin) { this.economicMin = economicMin; }
public String getCommitStatus() { return commitStatus; }
public BigDecimal getEconomicMax() { return economicMax; }
public BigDecimal getEconomicMin() { return economicMin; }
public AssetOwnedHourlyLocatableId getId() { return id; }
#Override
public AssetOwnedHourlyLocatableId getKey() {
return getId();
}
}
The AssetOwnedHourlyLocatableId is a compound id. It looks like...
public class AssetOwnedHourlyLocatableId implements Serializable, AssetOwned, HasHour, Locatable,
UniquelyKeyed<AssetOwnedHourlyLocatableId> {
private static final long serialVersionUID = 1L;
private String location;
private String hour;
private String assetOwner;
#Override
public String getLocation() {
return location;
}
#Override
public void setLocation(final String location) {
this.location = location;
}
#Override
public String getHour() {
return hour;
}
#Override
public void setHour(final String hour) {
this.hour = hour;
}
#Override
public String getAssetOwner() {
return assetOwner;
}
#Override
public void setAssetOwner(final String assetOwner) {
this.assetOwner = assetOwner;
}
}
I want to generate a grid where the hours are pivoted into column headers and the location is the only other additional column header.
E.g.,
Location 1 2 3 4 5 6 ... 24
would be the column headers.
Underneath each column you might see...
> L1
> Commit Status Status1 .... Status24
> Eco Min EcoMin1 .... EcoMin24
> Eco Max EcoMax1 .... EcoMax24
> L2
> Commit Status Status1 .... Status24
> Eco Min EcoMin1 .... EcoMin24
> Eco Max EcoMax1 .... EcoMax24
So, if I'm provided a List<DSRUpdateHourlyDTO> I want to convert it into the presentation format described above.
What would be the best way to do this?
I have a few additional functional requirements.
I want to be able to toggle between read-only and editable views of the same table.
I want to be able to complete a round-trip to a datasource (e.g., JPAContainerSource).
I (will eventually) want to filter items by any part of the compound id.
My challenge is in the adaptation. I well understand the simple use case where I could take the list and simply splat it into a BeanItemContainer and use addNestedContainerProperty and setVisibleColumns. Pivoting properties into columns seems to be what's stumping me.
As it turns out this was an ill-conceived question.
For data entry purposes, one could use a BeanItemContainer and have the columns include nested container property hour from the composite id and instead of a TreeTable, use a Table that has commitStatus, ecoMin and ecoMax as columns. Limitation: you'd only ever query for / submit one assetOwner and location's worth of data.
As for display, where you don't care to filter one assetOwner and location's worth of data, you could pivot the hour info as originally described. You could just convert the original bean into another bean suitable for display (where each hour is its own column).
I need to get the count of rows from a criteria query and the criteria got group by projections. (needed to get paging to work)
E.g.
projectionList.Add(Projections.GroupProperty("Col1"), "col1")
.Add(Projections.CountDistinct("Col2"), "Count");
I need to avoid CreateSQL, since I have a lot of criteria.. and the restrictions etc are complex.
Can you do a subcriteria (detached) and then select count(*) from .. ? Can't figure out how?
EDIT: I solved it by getting the sql from the criteria and then modifying it so that it now works! GetSql from criteria
Not entirely sure what you want, but something like this should work (if I understand your question properly):
var subQuery = DetachedCriteria.For<SomeClass>()
.Where(... add your conditions here ...);
var count = Session.CreateCriteria<SomeClass>()
.Where(Property.ForName("Col1").In(
CriteriaTransformer.Clone(subQuery).SetProjection(Projections.Property("Col1"))
.SetProjection(Projections.Count())
.FutureValue<int>();
var results = subQuery.GetExecutableCriteria(Session)
.SetProjection(Projections.GroupProperty("Col1"), "col1"),
Projections.CountDistinct("Col2"), "Count")
).List<object[]>();
Just to think a bit outside the box and remove the query complexity from NHiberate. You can make a View for the query in the database and then make a mapping for the view.
I think this can be done by using NH Multi Queries.
Here is some stuff about it: http://ayende.com/blog/3979/nhibernate-futures Example shows how we can run query and get results count of that query in one roundtrip to the database.
And here is good answer, which sounds similar to what you want to achieve: nhibernate 2.0 Efficient Data Paging DataList Control and ObjectDataSource in which they get the result page AND total records count in one roundtrip to the database.
Also, I doubt that it is possible to read pure ##rowcount value with NH without changing sql query, as ##rowcount is database specific thing.
My assumption would be that for your case it is not possible to avoid GetSql from criteria solution, unless you simplify your query or approach. Maybe it worth to try this as well.
If you can post bigger chunk of your code, probably someone will be able to figure this out.
I 've resolved this problem on the java version (Hibernate). The problem is that the RowProjection function is some like:
count(*)
That is an aggregate function: so if you create a 'group by' property your result is a list of the grouped row and for each row you have the total count of the group.
For me, with oracle database, to make it work i've create a custom projection that, instead of create function count(*), the function is
count(count(*))
and the property in the group by clause are not written in the select ... from statement. To do that it not that simple, the problem is that you have to provide all stack to create the right sql so, with the java version I've to subclasse 2 class:
SimpleProjection
ProjectionList
After that my query generated as:
select count(*), col1, col2 from table1 group by col1, col2
become
select count(count(*)) from table1 group by col1, col2
and the result are the total row given by
select col1, col2 from table1 group by col1, col2
(usable with pagination system)
I post here the java version of the classes, if are useful for you:
public class CustomProjectionList extends ProjectionList {
private static final long serialVersionUID = 5762155180392132152L;
#Override
public ProjectionList create() {
return new CustomProjectionList();
}
public static ProjectionList getNewCustomProjectionList() {
return new CustomProjectionList();
}
#Override
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) throws HibernateException {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < getLength(); i++) {
Projection proj = getProjection(i);
String sqlString = proj.toSqlString(criteria, loc, criteriaQuery);
buf.append(sqlString);
loc += getColumnAliases(loc, criteria, criteriaQuery, proj).length;
if (i < (getLength() - 1) && sqlString != null && sqlString.length() > 0)
buf.append(", ");
}
return buf.toString();
}
private static String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery, Projection projection) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( loc, criteria, criteriaQuery ) :
projection.getColumnAliases( loc );
}
}
public class CustomPropertyProjection extends SimpleProjection {
private static final long serialVersionUID = -5206671448535977079L;
private String propertyName;
private boolean grouped;
#Override
public String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
return new String[0];
}
#Override
public String[] getColumnAliases(int loc) {
return new String[0];
}
#Override
public int getColumnCount(Criteria criteria, CriteriaQuery criteriaQuery) {
return 0;
}
#Override
public String[] getAliases() {
return new String[0];
}
public CustomPropertyProjection(String prop, boolean grouped) {
this.propertyName = prop;
this.grouped = grouped;
}
protected CustomPropertyProjection(String prop) {
this(prop, false);
}
public String getPropertyName() {
return propertyName;
}
public String toString() {
return propertyName;
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return new Type[0];
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
throws HibernateException {
return "";
}
public boolean isGrouped() {
return grouped;
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
if (!grouped) {
return super.toGroupSqlString(criteria, criteriaQuery);
}
else {
return StringHelper.join( ", ", criteriaQuery.getColumns( propertyName, criteria ) );
}
}
}
public class CustomRowCountProjection extends SimpleProjection {
/**
*
*/
private static final long serialVersionUID = -7886296860233977609L;
#SuppressWarnings("rawtypes")
private static List ARGS = java.util.Collections.singletonList( "*" );
public CustomRowCountProjection() {
super();
}
public String toString() {
return "count(count(*))";
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new Type[] {
getFunction( criteriaQuery ).getReturnType( null, criteriaQuery.getFactory() )
};
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {
SQLFunction countSql = getFunction( criteriaQuery );
String sqlString = countSql.toString() + "(" + countSql.render( null, ARGS, criteriaQuery.getFactory() ) + ") as y" + position + '_';
return sqlString;
}
protected SQLFunction getFunction(CriteriaQuery criteriaQuery) {
SQLFunction function = criteriaQuery.getFactory()
.getSqlFunctionRegistry()
.findSQLFunction( "count" );
if ( function == null ) {
throw new HibernateException( "Unable to locate count function mapping" );
}
return function;
}
}
Hope this help.
We are using fluentnhibernate with automapping and we have a naming convention that all columns that are foreign keys, there column name will end with "Key". So we have a convention that looks like this:
public class ForeignKeyColumnNameConvention : IReferenceConvention
{
public void Apply ( IManyToOneInstance instance )
{
// name the key field
string propertyName = instance.Property.Name;
instance.Column ( propertyName + "Key" );
}
}
This works great until we created a component in which one of its values is a foreign key. By renaming the column here it overrides the default name given to the component column which includes the ComponentPrefix which is defined in the AutomappingConfiguration. Is there a way for me to get the ComponentPrefix in this convention? or is there some other way for me to get the column name for components with a property that is a foreign key to end in the word "Key"?
After a lot of fiddling and trial & error (thus being tempted to use your solution with Reflection) I came up with the following:
This method depends on the order of the execution of the conventions. This convention-order happens via a strict hierarchy. In this example, at first, the convention of the component (IDynamicComponentConvention) is being handled and after that the conventions of the inner properties are being handled such as the References mapping (IReferenceConvention).
The strict order is where we make our strike:
We assemble the correct name of the column in the call to Apply(IDynamicComponentConvention instance), put it on the queue. Note that a Queue<T> is used which is a FIFO (first-in-first-out) collection type thus it keeps the order correctly.
Almost immediately after that, Apply(IManyToOneInstanceinstance) is called. We check if there is anything in the queue. If there is, we take it out of the queue and set it as column name. Note that you should not use Peek() instead of Dequeue() as it does not remove the object from the queue.
The code is as follows:
public sealed class CustomNamingConvention : IDynamicComponentConvention, IReferenceConvention {
private static Queue<string> ColumnNames = new Queue<string>();
public void Apply(IDynamicComponentInstance instance) {
foreach (var referenceInspector in instance.References) {
// All the information we need is right here
// But only to inspect, no editing yet :(
// Don't worry, just assemble the name and enqueue it
var name = string.Format("{0}_{1}",
instance.Name,
referenceInspector.Columns.Single().Name);
ColumnNames.Enqueue(name);
}
}
public void Apply(IManyToOneInstance instance) {
if (!ColumnNames.Any())
// Nothing in the queue? Just return then (^_^)
return;
// Set the retrieved string as the column name
var columnName = ColumnNames.Dequeue();
instance.Column(columnName);
// Pick a beer and celebrate the correct naming!
}
}
I Have figured out a way to do this using reflection to get to the underlying mapping of the IManyToOneInspector exposed by the IComponentInstance but was hoping there was a better way to do this?
Here is some example code of how I achieved this:
#region IConvention<IComponentInspector, IComponentInstance> Members
public void Apply(IComponentInstance instance)
{
foreach (var manyToOneInspector in instance.References)
{
var referenceName = string.Format("{0}_{1}_{2}{3}", instance.EntityType.Name, manyToOneInspector.Property.PropertyType.Name, _autoMappingConfiguration.GetComponentColumnPrefix(instance.Property), manyToOneInspector.Property.Name);
if(manyToOneInspector.Property.PropertyType.IsSubclassOf(typeof(LookupBase)))
{
referenceName += "Lkp";
}
manyToOneInspector.Index ( string.Format ( "{0}_FK_IDX", referenceName ) );
}
}
#endregion
public static class ManyToOneInspectorExtensions
{
public static ManyToOneMapping GetMapping(this IManyToOneInspector manyToOneInspector)
{
var fieldInfo = manyToOneInspector.GetType ().GetField( "mapping", BindingFlags.NonPublic | BindingFlags.Instance );
if (fieldInfo != null)
{
var manyToOneMapping = fieldInfo.GetValue( manyToOneInspector ) as ManyToOneMapping;
return manyToOneMapping;
}
return null;
}
public static void Index(this IManyToOneInspector manyToOneInspector, string indexName)
{
var mapping = manyToOneInspector.GetMapping ();
mapping.Index ( indexName );
}
public static void Column(this IManyToOneInspector manyToOneInspector, string columnName)
{
var mapping = manyToOneInspector.GetMapping ();
mapping.Column ( columnName );
}
public static void ForeignKey(this IManyToOneInspector manyToOneInspector, string foreignKeyName)
{
var mapping = manyToOneInspector.GetMapping();
mapping.ForeignKey ( foreignKeyName );
}
}
public static class ManyToOneMappingExtensions
{
public static void Index (this ManyToOneMapping manyToOneMapping, string indexName)
{
if (manyToOneMapping.Columns.First().IsSpecified("Index"))
return;
foreach (var column in manyToOneMapping.Columns)
{
column.Index = indexName;
}
}
public static void Column(this ManyToOneMapping manyToOneMapping, string columnName)
{
if (manyToOneMapping.Columns.UserDefined.Count() > 0)
return;
var originalColumn = manyToOneMapping.Columns.FirstOrDefault();
var column = originalColumn == null ? new ColumnMapping() : originalColumn.Clone();
column.Name = columnName;
manyToOneMapping.ClearColumns();
manyToOneMapping.AddColumn(column);
}
public static void ForeignKey(this ManyToOneMapping manyToOneMapping, string foreignKeyName)
{
if (!manyToOneMapping.IsSpecified("ForeignKey"))
manyToOneMapping.ForeignKey = foreignKeyName;
}
}