mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Make Single Query for Nearby and WLM pins (#4573)
* Merge nearby and monument queries * Bug Fix- query resource path change on shouldQueryForMonuments * Bug Fixes 1. Propagate exceptions for nearby API calls to caller 2. Fix too much work on main thread exception in NearbyParentFragment
This commit is contained in:
parent
cba99ae5e3
commit
678bd33410
10 changed files with 148 additions and 187 deletions
|
|
@ -454,7 +454,7 @@ public class ContributionsFragment
|
|||
private void updateClosestNearbyCardViewInfo() {
|
||||
curLatLng = locationManager.getLastLocation();
|
||||
compositeDisposable.add(Observable.fromCallable(() -> nearbyController
|
||||
.loadAttractionsFromLocation(curLatLng, curLatLng, true, false)) // thanks to boolean, it will only return closest result
|
||||
.loadAttractionsFromLocation(curLatLng, curLatLng, true, false, false)) // thanks to boolean, it will only return closest result
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::updateNearbyNotification,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.UPDAT
|
|||
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.gson.Gson;
|
||||
import fr.free.nrw.commons.campaigns.CampaignResponseDTO;
|
||||
import fr.free.nrw.commons.explore.depictions.DepictsClient;
|
||||
|
|
@ -264,105 +265,52 @@ public class OkHttpJsonApiClient {
|
|||
});
|
||||
}
|
||||
|
||||
public Observable<List<Place>> getNearbyPlaces(LatLng cur, String language, double radius)
|
||||
@Nullable
|
||||
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
|
||||
final boolean shouldQueryForMonuments)
|
||||
throws Exception {
|
||||
|
||||
Timber.d("Fetching nearby items at radius %s", radius);
|
||||
String wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
||||
String query = wikidataQuery
|
||||
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
|
||||
.replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude()))
|
||||
.replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude()))
|
||||
.replace("${LANG}", language);
|
||||
|
||||
HttpUrl.Builder urlBuilder = HttpUrl
|
||||
.parse(sparqlQueryUrl)
|
||||
.newBuilder()
|
||||
.addQueryParameter("query", query)
|
||||
.addQueryParameter("format", "json");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.build())
|
||||
.build();
|
||||
|
||||
return Observable.fromCallable(() -> {
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
if (response != null && response.body() != null && response.isSuccessful()) {
|
||||
String json = response.body().string();
|
||||
if (json == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class);
|
||||
List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings();
|
||||
List<Place> places = new ArrayList<>();
|
||||
for (NearbyResultItem item : bindings) {
|
||||
places.add(Place.from(item));
|
||||
}
|
||||
return places;
|
||||
}
|
||||
return new ArrayList<>();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wikidata query to fetch monuments
|
||||
*
|
||||
* @param cur : The current location coordinates
|
||||
* @param language : The language
|
||||
* @param radius : The radius around the current location within which we expect the results
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Observable<List<Place>> getNearbyMonuments(LatLng cur, String language, final double radius){
|
||||
Timber.d("Fetching monuments at radius %s", radius);
|
||||
final String wikidataQuery;
|
||||
try {
|
||||
wikidataQuery = FileUtils.readFromResource("/queries/monuments_query.rq");
|
||||
if (TextUtils.isEmpty(language)) {
|
||||
language = "en";
|
||||
if (!shouldQueryForMonuments) {
|
||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
||||
} else {
|
||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
|
||||
}
|
||||
String query = wikidataQuery
|
||||
final String query = wikidataQuery
|
||||
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
|
||||
.replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude()))
|
||||
.replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude()))
|
||||
.replace("${LANG}", language);
|
||||
|
||||
HttpUrl.Builder urlBuilder = HttpUrl
|
||||
final HttpUrl.Builder urlBuilder = HttpUrl
|
||||
.parse(sparqlQueryUrl)
|
||||
.newBuilder()
|
||||
.addQueryParameter("query", query)
|
||||
.addQueryParameter("format", "json");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
final Request request = new Request.Builder()
|
||||
.url(urlBuilder.build())
|
||||
.build();
|
||||
|
||||
Timber.d("Monuments URL: %s", request.url().toString());
|
||||
|
||||
return Observable.fromCallable(() -> {
|
||||
final Response response = okHttpClient.newCall(request).execute();
|
||||
if (response != null && response.body() != null && response.isSuccessful()) {
|
||||
if (response.body() != null && response.isSuccessful()) {
|
||||
final String json = response.body().string();
|
||||
if (json == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class);
|
||||
final List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings();
|
||||
final List<Place> places = new ArrayList<>();
|
||||
for (final NearbyResultItem item : bindings) {
|
||||
final Place place = Place.from(item);
|
||||
place.setMonument(true);
|
||||
places.add(place);
|
||||
final Place placeFromNearbyItem = Place.from(item);
|
||||
if (shouldQueryForMonuments && item.getMonument() != null) {
|
||||
placeFromNearbyItem.setMonument(true);
|
||||
} else {
|
||||
placeFromNearbyItem.setMonument(false);
|
||||
}
|
||||
places.add(placeFromNearbyItem);
|
||||
}
|
||||
return places;
|
||||
}
|
||||
return new ArrayList<>();
|
||||
});
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
return Observable.error(e);
|
||||
}
|
||||
throw new Exception(response.message());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -57,7 +57,9 @@ public class NearbyController {
|
|||
* @return NearbyPlacesInfo a variable holds Place list without distance information
|
||||
* and boundary coordinates of current Place List
|
||||
*/
|
||||
public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng, LatLng searchLatLng, boolean returnClosestResult, boolean checkingAroundCurrentLocation) throws IOException {
|
||||
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng, final LatLng searchLatLng,
|
||||
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
|
||||
final boolean shouldQueryForMonuments) throws Exception {
|
||||
|
||||
Timber.d("Loading attractions near %s", searchLatLng);
|
||||
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
|
||||
|
|
@ -66,7 +68,9 @@ public class NearbyController {
|
|||
Timber.d("Loading attractions nearby, but curLatLng is null");
|
||||
return null;
|
||||
}
|
||||
List<Place> places = nearbyPlaces.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult);
|
||||
List<Place> places = nearbyPlaces
|
||||
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
|
||||
shouldQueryForMonuments);
|
||||
|
||||
if (null != places && places.size() > 0) {
|
||||
LatLng[] boundaryCoordinates = {places.get(0).location, // south
|
||||
|
|
@ -128,11 +132,6 @@ public class NearbyController {
|
|||
}
|
||||
}
|
||||
|
||||
public Observable<List<Place>> queryWikiDataForMonuments(
|
||||
final LatLng latLng, final String language) {
|
||||
return nearbyPlaces.queryWikiDataForMonuments(latLng, language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads attractions from location for list view, we need to return Place data type.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -41,12 +39,12 @@ public class NearbyPlaces {
|
|||
* @param lang user's language
|
||||
* @param returnClosestResult true if only the nearest point is desired
|
||||
* @return list of places obtained
|
||||
* @throws IOException if query fails
|
||||
*/
|
||||
List<Place> radiusExpander(LatLng curLatLng, String lang, boolean returnClosestResult) throws IOException {
|
||||
List<Place> radiusExpander(final LatLng curLatLng, final String lang, final boolean returnClosestResult
|
||||
, final boolean shouldQueryForMonuments) throws Exception {
|
||||
|
||||
int minResults;
|
||||
double maxRadius;
|
||||
final int minResults;
|
||||
final double maxRadius;
|
||||
|
||||
List<Place> places = Collections.emptyList();
|
||||
|
||||
|
|
@ -64,12 +62,7 @@ public class NearbyPlaces {
|
|||
|
||||
// Increase the radius gradually to find a satisfactory number of nearby places
|
||||
while (radius <= maxRadius) {
|
||||
try {
|
||||
places = getFromWikidataQuery(curLatLng, lang, radius);
|
||||
} catch (final Exception e) {
|
||||
Timber.e(e, "Exception in fetching nearby places");
|
||||
break;
|
||||
}
|
||||
places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments);
|
||||
Timber.d("%d results at radius: %f", places.size(), radius);
|
||||
if (places.size() >= minResults) {
|
||||
break;
|
||||
|
|
@ -89,16 +82,12 @@ public class NearbyPlaces {
|
|||
* @param cur coordinates of search location
|
||||
* @param lang user's language
|
||||
* @param radius radius for search, as determined by radiusExpander()
|
||||
* @param shouldQueryForMonuments should the query include properites for monuments
|
||||
* @return list of places obtained
|
||||
* @throws IOException if query fails
|
||||
*/
|
||||
public List<Place> getFromWikidataQuery(LatLng cur, String lang, double radius) throws Exception {
|
||||
return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius).blockingSingle();
|
||||
}
|
||||
|
||||
public Observable<List<Place>> queryWikiDataForMonuments(
|
||||
LatLng latLng, String language) {
|
||||
return okHttpJsonApiClient
|
||||
.getNearbyMonuments(latLng, language, radius);
|
||||
public List<Place> getFromWikidataQuery(final LatLng cur, final String lang,
|
||||
final double radius, final boolean shouldQueryForMonuments) throws Exception {
|
||||
return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius, shouldQueryForMonuments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -883,29 +883,11 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
|
||||
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
.loadAttractionsFromLocation(curlatLng, searchLatLng, false, true));
|
||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
||||
false, true, Utils.isMonumentsEnabled(new Date(), applicationKvStore)));
|
||||
|
||||
Observable<List<Place>> observableWikidataMonuments = Observable.empty();
|
||||
if(Utils.isMonumentsEnabled(new Date(), applicationKvStore)){
|
||||
observableWikidataMonuments =
|
||||
nearbyController
|
||||
.queryWikiDataForMonuments(searchLatLng, Locale.getDefault().getLanguage());
|
||||
|
||||
}
|
||||
|
||||
compositeDisposable.add(Observable.zip(nearbyPlacesInfoObservable
|
||||
, observableWikidataMonuments.onErrorReturn(throwable -> {
|
||||
showErrorMessage(getString(R.string.error_fetching_nearby_monuments) + throwable
|
||||
.getLocalizedMessage());
|
||||
return new ArrayList<>();
|
||||
}),
|
||||
(nearbyPlacesInfo, monuments) -> {
|
||||
final List<Place> places = mergeNearbyPlacesAndMonuments(nearbyPlacesInfo.placeList,
|
||||
monuments);
|
||||
nearbyPlacesInfo.placeList.clear();
|
||||
nearbyPlacesInfo.placeList.addAll(places);
|
||||
return nearbyPlacesInfo;
|
||||
}).subscribeOn(Schedulers.io())
|
||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(nearbyPlacesInfo -> {
|
||||
updateMapMarkers(nearbyPlacesInfo, true);
|
||||
|
|
@ -925,28 +907,11 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
|
||||
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
.loadAttractionsFromLocation(curlatLng, searchLatLng, false, false));
|
||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
||||
false, true, Utils.isMonumentsEnabled(new Date(), applicationKvStore)));
|
||||
|
||||
Observable<List<Place>> observableWikidataMonuments = Observable.empty();
|
||||
if (Utils.isMonumentsEnabled(new Date(), applicationKvStore)) {
|
||||
observableWikidataMonuments = nearbyController
|
||||
.queryWikiDataForMonuments(searchLatLng, Locale.getDefault().getLanguage());
|
||||
|
||||
}
|
||||
|
||||
compositeDisposable.add(Observable.zip(nearbyPlacesInfoObservable
|
||||
, observableWikidataMonuments.onErrorReturn(throwable -> {
|
||||
showErrorMessage(getString(R.string.error_fetching_nearby_monuments) + throwable
|
||||
.getLocalizedMessage());
|
||||
return new ArrayList<>();
|
||||
}),
|
||||
(nearbyPlacesInfo, monuments) -> {
|
||||
final List<Place> places = mergeNearbyPlacesAndMonuments(nearbyPlacesInfo.placeList,
|
||||
monuments);
|
||||
nearbyPlacesInfo.placeList.clear();
|
||||
nearbyPlacesInfo.placeList.addAll(places);
|
||||
return nearbyPlacesInfo;
|
||||
}).subscribeOn(Schedulers.io())
|
||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(nearbyPlacesInfo -> {
|
||||
updateMapMarkers(nearbyPlacesInfo, false);
|
||||
|
|
@ -961,25 +926,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* If a nearby place happens to be a monument as well, don't make the Pin's overlap, instead
|
||||
* show it as a monument
|
||||
*
|
||||
* @param nearbyPlaces
|
||||
* @param monuments
|
||||
* @return
|
||||
*/
|
||||
private List<Place> mergeNearbyPlacesAndMonuments(List<Place> nearbyPlaces, List<Place> monuments){
|
||||
List<Place> allPlaces= new ArrayList<>();
|
||||
allPlaces.addAll(monuments);
|
||||
for (Place place : nearbyPlaces){
|
||||
if(!allPlaces.contains(place)){
|
||||
allPlaces.add(place);
|
||||
}
|
||||
}
|
||||
return allPlaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates places for your location, should be used for finding nearby places around a
|
||||
* location where you are.
|
||||
|
|
@ -1238,7 +1184,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
public void addCurrentLocationMarker(final fr.free.nrw.commons.location.LatLng curLatLng) {
|
||||
if (null != curLatLng && !isPermissionDenied) {
|
||||
ExecutorUtils.get().submit(() -> {
|
||||
mapView.post(() -> removeCurrentLocationMarker());
|
||||
removeCurrentLocationMarker();
|
||||
Timber.d("Adds current location marker");
|
||||
|
||||
final Icon icon = IconFactory.getInstance(getContext())
|
||||
|
|
@ -1248,8 +1194,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
.position(new LatLng(curLatLng.getLatitude(),
|
||||
curLatLng.getLongitude()));
|
||||
currentLocationMarkerOptions.setIcon(icon); // Set custom icon
|
||||
mapView.post(() -> currentLocationMarker = mapBox.addMarker(currentLocationMarkerOptions));
|
||||
|
||||
currentLocationMarker = mapBox.addMarker(currentLocationMarkerOptions);
|
||||
|
||||
final List<LatLng> circle = UiUtils
|
||||
.createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
||||
|
|
@ -1259,7 +1204,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
.addAll(circle)
|
||||
.strokeColor(getResources().getColor(R.color.current_marker_stroke))
|
||||
.fillColor(getResources().getColor(R.color.current_marker_fill));
|
||||
mapView.post(() -> currentLocationPolygon = mapBox.addPolygon(currentLocationPolygonOptions));
|
||||
currentLocationPolygon = mapBox.addPolygon(currentLocationPolygonOptions);
|
||||
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ class NearbyResultItem(private val item: ResultTuple?,
|
|||
@field:SerializedName("pic") private val pic: ResultTuple?,
|
||||
@field:SerializedName("destroyed") private val destroyed: ResultTuple?,
|
||||
@field:SerializedName("description") private val description: ResultTuple?,
|
||||
@field:SerializedName("endTime") private val endTime: ResultTuple?) {
|
||||
@field:SerializedName("endTime") private val endTime: ResultTuple?,
|
||||
@field:SerializedName("monument") private val monument: ResultTuple?) {
|
||||
|
||||
fun getItem(): ResultTuple {
|
||||
return item ?: ResultTuple()
|
||||
|
|
@ -71,4 +72,8 @@ class NearbyResultItem(private val item: ResultTuple?,
|
|||
fun getAddress(): String {
|
||||
return address?.value?:""
|
||||
}
|
||||
|
||||
fun getMonument():ResultTuple?{
|
||||
return monument
|
||||
}
|
||||
}
|
||||
|
|
@ -283,13 +283,14 @@ public class UploadRepository {
|
|||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Place checkNearbyPlaces(double decLatitude, double decLongitude) {
|
||||
public Place checkNearbyPlaces(final double decLatitude, final double decLongitude) {
|
||||
try {
|
||||
List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
|
||||
final List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
|
||||
decLatitude, decLongitude, 0.0f),
|
||||
Locale.getDefault().getLanguage(),
|
||||
NEARBY_RADIUS_IN_KILO_METERS);
|
||||
return fromWikidataQuery.size() > 0 ? fromWikidataQuery.get(0) : null;
|
||||
NEARBY_RADIUS_IN_KILO_METERS, false);
|
||||
return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery
|
||||
.get(0) : null;
|
||||
}catch (final Exception e) {
|
||||
Timber.e("Error fetching nearby places: %s", e.getMessage());
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -199,12 +199,15 @@ class FileProcessor @Inject constructor(
|
|||
private fun suggestNearbyDepictions(imageCoordinates: ImageCoordinates): Disposable {
|
||||
return Observable.fromIterable(radiiProgressionInMetres.map { it / 1000.0 })
|
||||
.concatMap {
|
||||
Observable.fromCallable {
|
||||
okHttpJsonApiClient.getNearbyPlaces(
|
||||
imageCoordinates.latLng,
|
||||
Locale.getDefault().language,
|
||||
it
|
||||
it,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.filter { it.size >= MIN_NEARBY_RESULTS }
|
||||
.take(1)
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
|||
* This method checks for the nearest location that needs images and suggests it to the user.
|
||||
* @param uploadItem
|
||||
*/
|
||||
private void checkNearbyPlaces(UploadItem uploadItem) {
|
||||
Disposable checkNearbyPlaces = Maybe.fromCallable(() -> repository
|
||||
private void checkNearbyPlaces(final UploadItem uploadItem) {
|
||||
final Disposable checkNearbyPlaces = Maybe.fromCallable(() -> repository
|
||||
.checkNearbyPlaces(uploadItem.getGpsCoords().getDecLatitude(),
|
||||
uploadItem.getGpsCoords().getDecLongitude()))
|
||||
.subscribeOn(ioScheduler)
|
||||
|
|
|
|||
71
app/src/main/resources/queries/nearby_query_monuments.rq
Normal file
71
app/src/main/resources/queries/nearby_query_monuments.rq
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
SELECT
|
||||
(SAMPLE(?location) as ?location)
|
||||
?item
|
||||
(SAMPLE(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage)) as ?label)
|
||||
(SAMPLE(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?")) as ?description)
|
||||
(SAMPLE(?classId) as ?class)
|
||||
(SAMPLE(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?")) as ?classLabel)
|
||||
(SAMPLE(COALESCE(?icon0, ?icon1)) as ?icon)
|
||||
?wikipediaArticle
|
||||
?commonsArticle
|
||||
(SAMPLE(?commonsCategory) as ?commonsCategory)
|
||||
(SAMPLE(?pic) as ?pic)
|
||||
(SAMPLE(?destroyed) as ?destroyed)
|
||||
(SAMPLE(?endTime) as ?endTime)
|
||||
(SAMPLE(?monument) as ?monument)
|
||||
WHERE {
|
||||
# Around given location...
|
||||
SERVICE wikibase:around {
|
||||
?item wdt:P625 ?location.
|
||||
bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral.
|
||||
bd:serviceParam wikibase:radius "${RAD}" . # Radius in kilometers.
|
||||
}
|
||||
|
||||
OPTIONAL {
|
||||
{ ?item p:P1435 ?monument } UNION { ?item p:P2186 ?monument } UNION { ?item p:P1459 ?monument } UNION { ?item p:P1460 ?monument } UNION { ?item p:P1216 ?monument } UNION { ?item p:P709 ?monument } UNION { ?item p:P718 ?monument } UNION { ?item p:P5694 ?monument }
|
||||
}
|
||||
|
||||
# Get the label in the preferred language of the user, or any other language if no label is available in that language.
|
||||
OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "${LANG}")}
|
||||
OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage}
|
||||
|
||||
# Get the description in the preferred language of the user, or any other language if no description is available in that language.
|
||||
OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")}
|
||||
OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage }
|
||||
|
||||
# Get Commons category (P373)
|
||||
OPTIONAL { ?item wdt:P373 ?commonsCategory. }
|
||||
|
||||
# Get (P18)
|
||||
OPTIONAL { ?item wdt:P18 ?pic. }
|
||||
|
||||
# Get (P576)
|
||||
OPTIONAL { ?item wdt:P576 ?destroyed. }
|
||||
|
||||
# Get (P582)
|
||||
OPTIONAL { ?item wdt:P582 ?endTime. }
|
||||
|
||||
# Get the class label in the preferred language of the user, or any other language if no label is available in that language.
|
||||
OPTIONAL {
|
||||
?item p:P31/ps:P31 ?classId.
|
||||
OPTIONAL {?classId rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "${LANG}")}
|
||||
OPTIONAL {?classId rdfs:label ?classLabelAnyLanguage}
|
||||
|
||||
OPTIONAL {
|
||||
?wikipediaArticle schema:about ?item ;
|
||||
schema:isPartOf <https://${LANG}.wikipedia.org/> .
|
||||
}
|
||||
OPTIONAL {
|
||||
?wikipediaArticle schema:about ?item ;
|
||||
schema:isPartOf <https://en.wikipedia.org/> .
|
||||
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
|
||||
}
|
||||
|
||||
OPTIONAL {
|
||||
?commonsArticle schema:about ?item ;
|
||||
schema:isPartOf <https://commons.wikimedia.org/> .
|
||||
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
|
||||
}
|
||||
}
|
||||
}
|
||||
GROUP BY ?item ?wikipediaArticle ?commonsArticle
|
||||
Loading…
Add table
Add a link
Reference in a new issue