aboutsummaryrefslogtreecommitdiffstats
path: root/searchsummary/src/vespa/searchsummary/docsummary/geoposdfw.cpp
blob: 1a6b4ed69d86962d1a653915b3831c63e9df8f18 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "geoposdfw.h"
#include <vespa/searchlib/common/documentlocations.h>
#include <vespa/searchlib/attribute/iattributemanager.h>
#include <vespa/searchlib/common/location.h>
#include <vespa/vespalib/util/jsonwriter.h>
#include <vespa/vespalib/data/slime/cursor.h>
#include <vespa/vespalib/data/slime/inserter.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/issue.h>
#include <climits>
#include <cassert>

#include <vespa/log/log.h>
LOG_SETUP(".searchlib.docsummary.geoposdfw");

namespace search::docsummary {

using attribute::IAttributeVector;
using attribute::IAttributeContext;
using vespalib::Issue;

GeoPositionDFW::GeoPositionDFW(const vespalib::string & attrName, bool useV8geoPositions) :
    AttrDFW(attrName),
    _useV8geoPositions(useV8geoPositions)
{ }

namespace {

double to_degrees(int32_t microDegrees) {
    double d = microDegrees / 1.0e6;
    return d;
}

void fmtZcurve(int64_t zval, vespalib::slime::Inserter &target, bool useV8geoPositions) {
    int32_t docx = 0;
    int32_t docy = 0;
    vespalib::geo::ZCurve::decode(zval, &docx, &docy);
    if (docx == 0 && docy == INT_MIN) {
        LOG(spam, "skipping empty zcurve value");
    } else {
        vespalib::slime::Cursor &obj = target.insertObject();
        if (useV8geoPositions) {
            double degrees_ns = to_degrees(docy);
            double degrees_ew = to_degrees(docx);
            obj.setDouble("lat", degrees_ns);
            obj.setDouble("lng", degrees_ew);
        } else {
            obj.setLong("y", docy);
            obj.setLong("x", docx);
        }
    }
}

}

void
GeoPositionDFW::insertField(uint32_t docid, GetDocsumsState& dsState, vespalib::slime::Inserter &target) const
{
    using vespalib::slime::Cursor;
    using vespalib::slime::ObjectSymbolInserter;
    using vespalib::slime::Symbol;
    using vespalib::slime::ArrayInserter;

    const auto& attribute = get_attribute(dsState);
    if (attribute.hasMultiValue()) {
        uint32_t entries = attribute.getValueCount(docid);
        if (entries == 0 && _useV8geoPositions) return;
        Cursor &arr = target.insertArray();
        if (attribute.hasWeightedSetType()) {
            Symbol isym = arr.resolve("item");
            Symbol wsym = arr.resolve("weight");
            std::vector<IAttributeVector::WeightedInt> elements(entries);
            entries = attribute.get(docid, &elements[0], entries);
            for (uint32_t i = 0; i < entries; ++i) {
                Cursor &elem = arr.addObject();
                int64_t pos = elements[i].getValue();
                ObjectSymbolInserter obj(elem, isym);
                fmtZcurve(pos, obj, _useV8geoPositions);
                elem.setLong(wsym, elements[i].getWeight());
            }
        } else {
            std::vector<IAttributeVector::largeint_t> elements(16);
            uint32_t numValues = attribute.get(docid, &elements[0], elements.size());
            if (numValues > elements.size()) {
                elements.resize(numValues);
                numValues = attribute.get(docid, &elements[0], elements.size());
                assert(numValues <= elements.size());
            }
            for (uint32_t i = 0; i < numValues; i++) {
                int64_t pos = elements[i];
                ArrayInserter obj(arr);
                fmtZcurve(pos, obj, _useV8geoPositions);
            }
        }
    } else {
        int64_t pos = attribute.getInt(docid);
        fmtZcurve(pos, target, _useV8geoPositions);
    }
}

GeoPositionDFW::UP
GeoPositionDFW::create(const char *attribute_name,
                       const IAttributeManager *attribute_manager,
                       bool useV8geoPositions)
{
    if (attribute_manager != nullptr) {
        if (!attribute_name) {
            LOG(warning, "create: missing attribute name '%p'", attribute_name);
            return {};
        }
        IAttributeContext::UP context = attribute_manager->createContext();
        if (!context.get()) {
            LOG(warning, "create: could not create context from attribute manager");
            return {};
        }
        const IAttributeVector *attribute = context->getAttribute(attribute_name);
        if (!attribute) {
            Issue::report("GeoPositionDFW::create: could not get attribute '%s' from context", attribute_name);
            return {};
        }
    }
    return std::make_unique<GeoPositionDFW>(attribute_name, useV8geoPositions);
}

}