The SOLR engine contains a range of features you can use to carry out location based searches. This article looks at the different ways you can pass location related functions and queries to SOLR using the iCMAPI worker and CSSearchMultiple. The full SOLR documentation can be found at SOLR Spatial Search (opens new window).
Storing Location Based Data
Before you can start searching for locations, you'll need to index some location data in your SOLR collection.
The examples in this article all use a set of iCM objects, of a type called
In reality you're more likely to be searching for iCM articles that have location data saved in their article extras (the GOSS event location template does this) or you may have indexed a custom collection, brining non-iCM content and location data into your SOLR instance.
Searching and Sorting by Distance from a Point
When content is returned from SOLR one of the standard properties is a "score". This is used to indicate the relevance of an item to the query.
When you use the
To pass a SOLR function as a query, you need to set your function as the
Example
This request is made in the "Search for Objects with Location Data" example form related to this article.
client.invoke("icmapi", "CSSearchMultiple_get", {
"set": {
"CollectionNameList": "Object",
"LuceneRepositoryPath": "http://localhost:5506/solrsite",
"SearchCommand": "{!func}geodist()",
"FilterQueries": ["custom1:FORM_OBJECTSWITHLOCATIONS"],
"SolrParameters": [{
Name: "pt",
Value: ptValue
}, {
Name: "sfield",
Value: "OBJECT_LL_LOCATION"
}, {
Name: "sort",
Value: "score asc"
}]
},
"get": "*"
});
The
The final SOLR parameter is sort, and as the score is now the distance, we can sort by that. Use
And our results:
"result": {
"data": {
"multipleItemData": [{
"ParentData": "",
"CreationDate": "2018-02-26T13:45:55Z",
"_ItemClass": "CSSearchItem",
"GroupKey": "Object18948",
"Title": "FORM_OBJECTSWITHLOCATIONS,{ts '2018-02-26 13:45:55'},TIMG",
"Url": "E4112954-048A-4D70-93FD-941A8C565910",
"Custom3": "",
"Score": 1295.2273,
"Custom2": "1",
"Type": "Object",
"Custom1": "FORM_OBJECTSWITHLOCATIONS",
"ModificationDate": "2018-02-26T13:45:55Z",
"MetaData": "",
"DynamicFields": {
"OBJECT_C__icmTypeName": "FORM_OBJECTSWITHLOCATIONS",
"OBJECT_C__icmCreatedBy": "TIMG",
"OBJECT_C_LOCATIONNAME": "Plymouth",
"OBJECT_LL_LOCATION": "50.3754565,-4.1426565",
"OBJECT_C__title": "FORM_OBJECTSWITHLOCATIONS,{ts '2018-02-26 13:45:55'},TIMG",
"OBJECT_C__icmPublicType": "1",
"OBJECT_C__icmLastUpdatedBy": "TIMG"
},
"Summary": "FORM_OBJECTSWITHLOCATIONS E4112954-048A-4D70-93FD-941A8C565910",
"Key": "18948"
}, {
"ParentData": "",
"CreationDate": "2018-02-26T13:49:17Z",
"_ItemClass": "CSSearchItem",
"GroupKey": "Object18951",
"Title": "FORM_OBJECTSWITHLOCATIONS,{ts '2018-02-26 13:49:17'},TIMG",
"Url": "93E51183-BD02-40F7-BC14-EF801ECC20EF",
"Custom3": "",
"Score": 4478.3013,
"Custom2": "1",
"Type": "Object",
"Custom1": "FORM_OBJECTSWITHLOCATIONS",
"ModificationDate": "2018-02-26T13:49:17Z",
"MetaData": "",
"DynamicFields": {
"OBJECT_C__icmTypeName": "FORM_OBJECTSWITHLOCATIONS",
"OBJECT_C__icmCreatedBy": "TIMG",
"OBJECT_C_LOCATIONNAME": "Torquay",
"OBJECT_LL_LOCATION": "50.4619209,-3.525315",
"OBJECT_C__title": "FORM_OBJECTSWITHLOCATIONS,{ts '2018-02-26 13:49:17'},TIMG",
"OBJECT_C__icmPublicType": "1",
"OBJECT_C__icmLastUpdatedBy": "TIMG"
},
"Summary": "FORM_OBJECTSWITHLOCATIONS 93E51183-BD02-40F7-BC14-EF801ECC20EF",
"Key": "18951"
}]
},
"success": true
}
You can see the two properties of the object,
Filtering
The second example form builds on the location search above. It uses the same
"FilterQueries": ["custom1:FORM_OBJECTSWITHLOCATIONS","{!geofilt sfield=OBJECT_LL_LOCATION pt=50.2781708303,-4.3707226562 d=40}"]
The first query restricts the search to objects called
SOLR's documentation for
Grouping
The CSSearchMultiple
Geo Filters as Groups
Using the same structure as the filter query above, an array of geo filters could be added as group queries. In this example the field that holds location data hasn't been renamed, it's just FIELD2.
"GroupQueries": ["{!geofilt sfield=OBJECT_LL_FIELD2 pt=50.4233524,-4.0965925 d=0.1}", "{!geofilt sfield=OBJECT_LL_FIELD2 pt=50.4233524,-4.0965925 d=10}", "{!geofilt sfield=OBJECT_LL_FIELD2 pt=50.4233524,-4.0965925 d=20}", "{!geofilt sfield=OBJECT_LL_FIELD2 pt=50.4233524,-4.0965925 d=30}", "{!geofilt sfield=OBJECT_LL_FIELD2 pt=50.4233524,-4.0965925 d=40}", "{!geofilt sfield=OBJECT_LL_FIELD2 pt=50.4233524,-4.0965925 d=50}"]
This will create groups of results at 10, 20, 30, 40 and 50 kilometres.
The third example form related to this article uses
Ranges as Groups
The frange parser restricts results to a range of values found in a declared field or function query. Ranges are set in kilometres between a lower (
"GroupQueries": ["{!frange l=0 u=50} geodist(OBJECT_LL_LOCATION, 50.4233524,-4.0965925)","{!frange l=50 u=100} geodist(OBJECT_LL_LOCATION, 50.4233524,-4.0965925)","{!frange l=100 u=150} geodist(OBJECT_LL_LOCATION, 50.4233524,-4.0965925)","{!frange l=150 u=200} geodist(OBJECT_LL_LOCATION, 50.4233524,-4.0965925)","{!frange l=200 u=250} geodist(OBJECT_LL_LOCATION, 50.4233524,-4.0965925)"];
Each group query defines a range and a distance function that includes the field in our search items that holds lat/long values and the point we want to measure from.