// Build an FL_Link result from a list of SolrDocuments returned from a group command in a query protected FL_Link buildResultFromGroupedDocuments(SolrDocumentList dl) { // Build the initial result from the first document FL_Link link = buildResultFromDocument(dl.get(0)); // Get the nodetype String targetField = PropertyDescriptorHelper.mapKey( FL_RequiredPropertyKey.TO.name(), _applicationConfiguration.getLinkDescriptors().getProperties(), link.getType()); // Add the remaining document properties to the entity // Currently only the TO field is aggregated from grouping of one-to-many links for (int i = 1; i < dl.size(); i++) { SolrDocument sd = dl.get(i); String target = (String) sd.getFieldValue(targetField); FL_Property property = null; List<FL_Property> properties = link.getProperties(); for (FL_Property prop : link.getProperties()) { if (prop.getKey().equals(FL_RequiredPropertyKey.TO.name())) { property = prop; } } if (property != null) { Object range = property.getRange(); if (range instanceof FL_ListRange) { List<Object> values = ((FL_ListRange) range).getValues(); values.add(target); } else if (range instanceof FL_SingletonRange) { List<Object> values = new ArrayList<Object>(); values.add(((FL_SingletonRange) range).getValue()); values.add(target); property.setRange( FL_ListRange.newBuilder().setType(FL_PropertyType.STRING).setValues(values).build()); } link.setProperties(properties); } link.setTarget(link.getTarget() + "," + getTarget(sd)); } return link; }
@Override protected FL_Entity buildEntityFromDocument(SolrDocument sd) { FL_Entity.Builder entityBuilder = FL_Entity.newBuilder(); List<FL_Property> props = new ArrayList<FL_Property>(); List<FL_EntityTag> etags = new ArrayList<FL_EntityTag>(); String uid = (String) sd.getFieldValue("id"); entityBuilder.setProvenance(null); entityBuilder.setUncertainty(null); // Kiva specific type handling String type = ""; if (uid.startsWith("l")) { type = "lender"; } else if (uid.startsWith("b")) { type = "loan"; } else if (uid.startsWith("p")) { type = "partner"; } props.add( FL_Property.newBuilder() .setKey("type") .setFriendlyText("Kiva Account Type") .setProvenance(null) .setUncertainty(null) .setTags(Collections.singletonList(FL_PropertyTag.TYPE)) .setRange(new SingletonRangeHelper(type, FL_PropertyType.STRING)) .build()); List<Object> imageIds = new ArrayList<Object>(); if (type.equals("lender")) { imageIds.add("726677"); } else { imageIds.addAll(sd.getFieldValues("image_id")); } // --- FEATURE DEMOS ------------------------------------------ // Prompt for details if (uid.equals("leivind")) { etags.add(FL_EntityTag.PROMPT_FOR_DETAILS); } // Multiple image carousel if (uid.equals("b150236")) { imageIds.add("146773"); imageIds.add("148448"); } // Make lenders parchmenty if (type.equals("lender")) { final double notVeryConfidentDemonstration = 0.4 * Math.random(); entityBuilder.setUncertainty( FL_Uncertainty.newBuilder().setConfidence(notVeryConfidentDemonstration).build()); } // ------------------------------------------------------------ List<Object> imageURLs = new ArrayList<Object>(); for (Object url : imageIds) { imageURLs.add(_imageURLPrefix + url.toString() + ".jpg"); } Object values = FL_ListRange.newBuilder().setType(FL_PropertyType.STRING).setValues(imageURLs).build(); props.add( FL_Property.newBuilder() .setKey("image") .setFriendlyText("Image") .setProvenance(null) .setUncertainty(null) .setTags(Collections.singletonList(FL_PropertyTag.IMAGE)) .setRange(values) .build()); // ------------------------------------------------------------ // TODO : get tags once added to solr. // Read and build properties. Map<String, Collection<Object>> docValues = sd.getFieldValuesMap(); FL_GeoData.Builder geoBuilder = FL_GeoData.newBuilder().setCc("").setLat(0.0).setLon(0.0).setText(""); FL_Property.Builder propBuilder; FL_PropertyTag[] tags; List<FL_PropertyTag> ltags; boolean geoDataFound = false; String label = null; for (String key : docValues.keySet()) { if ("score".equals(key)) continue; // Skip the score, it does not belong in the entity object if (type.equals("lender") && LENDER_IGNORE_FIELDS.contains(key)) { continue; } // create a FL_GeoData builder in which the known geo fields can be placed. // Set default values; for (Object val : docValues.get(key)) { // special case handling for geodata if (key.equals("lender_whereabouts") || key.equals("loans_location_town") || key.equals("loans_location_country")) { String cleanVal = val.toString().trim(); if (!cleanVal.isEmpty()) { geoBuilder.setText( geoBuilder.getText().isEmpty() ? cleanVal : geoBuilder.getText() + ", " + cleanVal); geoDataFound = true; } // continue; } else if (key.equals("lenders_countryCode") || key.equals("loans_location_countryCode") || key.equals("partners_cc")) { String cleanVal = val.toString().replaceAll(",", " ").trim(); // correct kiva's invented country code for south sudan with the now official iso standard cleanVal = cleanVal.replaceAll("QS", "SS"); if (!cleanVal.isEmpty()) { geoBuilder.setCc( geoBuilder.getCc().isEmpty() ? cleanVal : geoBuilder.getCc() + " " + cleanVal); geoDataFound = true; } // continue; } else if (key.equals("lat")) { geoBuilder.setLat((Double) val); geoDataFound = true; // continue; } else if (key.equals("lon")) { geoBuilder.setLon((Double) val); geoDataFound = true; // continue; } propBuilder = FL_Property.newBuilder(); propBuilder.setKey(key); KivaPropertyMapping keyMapping = KivaPropertyMaps.INSTANCE.getPropMap().get(key); if (val instanceof Collection) { getLogger().warn("Prop " + key + " has a " + val.getClass() + " value, skipping for now"); continue; } else { if (keyMapping != null) { String friendlyName = KivaPropertyMaps.INSTANCE.getPropMap().get(key).getFriendlyName(); propBuilder.setFriendlyText(friendlyName); } else { propBuilder.setFriendlyText(key); } } propBuilder.setProvenance(null); propBuilder.setUncertainty(null); tags = null; if (keyMapping != null) { tags = keyMapping.getPropertyTags(); } if (tags == null || tags.length == 0) { ltags = new ArrayList<FL_PropertyTag>(); ltags.add(FL_PropertyTag.RAW); propBuilder.setTags(ltags); } else { ltags = Arrays.asList(tags); propBuilder.setTags(ltags); } /*if ((val instanceof Integer) || (val instanceof Long)) { val = val.toString()+"L"; }*/ // Special case value handling - jodatime if (val instanceof Date) { propBuilder.setRange( new SingletonRangeHelper(((Date) val).getTime(), FL_PropertyType.DATE)); } else if (val instanceof DateTime) { propBuilder.setRange( new SingletonRangeHelper(((DateTime) val).getMillis(), FL_PropertyType.DATE)); } else { propBuilder.setRange(new SingletonRangeHelper(val, FL_PropertyType.OTHER)); } props.add(propBuilder.build()); } // Added to resolve #6245; I am not terribly familiar with the inner workings of the back end, // so feel // free to refactor this if it isn't the best place to assign the value of 'label' if (label == null && docValues.get(key).size() > 0 && (key.equals("lenders_name") || key.equals("partners_name") || key.equals("loans_name") || key.equals("teams_name"))) { Object value = docValues.get(key).iterator().next(); if (value != null) { label = value.toString(); } } } // Build the geo property if geo data was found if (geoDataFound) { String trimmed = geoBuilder.getText(); if (trimmed != null) { trimmed = trimmed.trim(); if (!trimmed.isEmpty()) { label += ". " + trimmed; } } FL_GeoData flgd = geoBuilder.build(); List<FL_GeoData> geos; // multiple values here. break them up. if (flgd.getCc() != null && flgd.getCc().indexOf(' ') != -1) { String ccs[] = flgd.getCc().split(" "); geos = new ArrayList<FL_GeoData>(ccs.length); for (int j = 0; j < ccs.length; j++) { geos.add(new FL_GeoData(flgd.getText(), flgd.getLat(), flgd.getLon(), ccs[j])); } } else { geos = Collections.singletonList(flgd); } try { _geocoding.geocode(geos); } catch (AvroRemoteException e) { getLogger().info("Failed to geocode entity", e); } Object geoVal = (geos.size() > 1) ? FL_ListRange.newBuilder() .setType(FL_PropertyType.GEO) .setValues(Arrays.asList(geos.toArray())) .build() : new SingletonRangeHelper(geos.get(0), FL_PropertyType.GEO); FL_Property geoProp = FL_Property.newBuilder() .setKey("geo") .setFriendlyText("") .setTags(Collections.singletonList(FL_PropertyTag.GEO)) .setRange(geoVal) .setProvenance(null) .setUncertainty(null) .build(); props.add(geoProp); } propBuilder = FL_Property.newBuilder() .setKey("label") .setFriendlyText("label") .setProvenance(null) .setUncertainty(null) .setTags(Collections.singletonList(FL_PropertyTag.LABEL)) .setRange(new SingletonRangeHelper(label, FL_PropertyType.STRING)); props.add(propBuilder.build()); if (type.equals("partner")) { KivaPropertyMaps.INSTANCE.appendPartnerProperties(props); etags.add(FL_EntityTag.ACCOUNT_OWNER); // partners are account owners entityBuilder.setUid(TypedId.fromNativeId(TypedId.ACCOUNT_OWNER, uid).getTypedId()); // determine whether this a large account owner and if there is a cluster summary associated final FL_Property numLoans = PropertyHelper.getPropertyByKey(props, "partners_loansPosted"); if (numLoans != null) { final Number number = (Number) PropertyHelper.from(numLoans).getValue(); if (number != null && number.intValue() >= 1000) { props.add( new PropertyHelper( FL_PropertyTag.CLUSTER_SUMMARY, TypedId.fromNativeId(TypedId.CLUSTER_SUMMARY, 's' + uid).getTypedId())); entityBuilder.setUid(TypedId.fromNativeId(TypedId.CLUSTER_SUMMARY, uid).getTypedId()); } } } else { etags.add(FL_EntityTag.ACCOUNT); // all others are raw accounts entityBuilder.setUid(TypedId.fromNativeId(TypedId.ACCOUNT, uid).getTypedId()); } entityBuilder.setTags(etags); entityBuilder.setProperties(props); return entityBuilder.build(); }