I am trying to return a certain set of values however the query is not quite returning what I would like. I would like to return records by the author "Hennie J. Steenhagen" grouped by year. However what it is returning is records grouped by year if it’s of the same year as one of Hennies records. Not only Hennies.
For example, if we have the record <www><author>Hennie*</author><year>1990</year></www> and <www><author>Derpie</author><year>1990></year></www> the query will return both records grouped in the year 1990, I would only like Hennies to be returned.
for $y in /*/*/year where $y/../author ="Hennie J. Steenhagen" return <year-Pub>{$y}{/*/*[year = $y]}</year-Pub>
Your question is quite difficult to understand because your XPath addresses a larger XML node tree than the example XML you have provided. However for the example I will assume that your records are named record. Also your output of your XPath does not make a lot of sense to me, but I will assume that you know what you want!
Given the XML:
<record>
<www>
<author>Hennie J. Steenhagen</author>
<year>1990</year>
</www>
and
<www>
<author>Derpie</author>
<year>1990></year>
</www>
</record>
If you have an XQuery 3.0 processor, you could use the following:
/record/www[author = "Hennie J. Steenhagen"] ! <year-Pub>{year}{.}</year-Pub>
If you only have access to an XQuery 1.0 processor, then you could fall-back to the following:
for $w in /record/www[author = "Hennie J. Steenhagen"]
return
<year-Pub>{$w/year}{$w}</year-Pub>
Both of my examples only use a single predicate which will only filter the data once. Whereas your self-found solution uses both a predicate and a where expression, and so has to filter the data twice.
Fixed it,
for $y in /*/*/year where $y/../author ="Hennie J. Steenhagen" and /*/*[year=$y] return <year-Pub>{$y/../*}</year-Pub>
Thanks for any one whom spend their time looking.
Related
I have a table of data similar to:
where I'd like to get just the shapes which match a set of given criteria (in this case week=2 and colour=blue).
I can return the first result using index and match like:
=ArrayFormula(INDEX(C2:C14,MATCH($F$1&$F$2,A2:A14&B2:B14,0)))
but I'd like to return the all matching values (eg square and triangle) in to the range F3:Fsomething. This would preferably be done using a formula that returns a range and isn't "copied-down", as a list of all possible shapes isn't known beforehand.
How can I modify this formula to achieve this?
See if this works:
=FILTER (C2:C14, B2:B14=F2, A2:A14=F1)
to do multiple criteria you want to use * like so
=FILTER (C2:C14, (B2:B14=F2) * (A2:A14=F1))
and if you want the results all in the same cell with a delimiter, use TEXTJOIN
=TEXTJOIN([DELIMETER],[IGNORE EMPTY TEXT],text1)
=TEXTJOIN(", ",TRUE,FILTER(C2:C14,(B2:B14=F2)*(A2:A14=F1)))
I am using Sitecore 7.2 with a custom Lucene index and Linq. I need to give additional (maximum) weight to exact matches.
Example:
A user searches for "somewhere over the rainbow"
Results should include items which contain the word "rainbow", but items containing the exact and entire term "somewhere over the rainbow" should be given maximum weight. They will displayed to users as the top results. i.e. An item containing the entire phrase should weigh more heavily than an item which contains the word "rainbow" 100 times.
I may need to handle ranking logic outside of the ContentSearch API by collecting "phrase matches" separately from "wildcard matches", and that's fine.
Here's my existing code, truncated for brevity. The code works, but exact phrase matches are not treated as I described.
using (var context = ContentSearchManager.GetIndex("sitesearch-index").CreateSearchContext())
{
var pred = PredicateBuilder.False<SearchResultItem>();
pred = pred
.Or(i => i.Name.Contains(term)).Boost(1)
.Or(i => i["Field 1"].Contains(term)).Boost(3)
.Or(i => i["Field 2"].Contains(term)).Boost(1);
IQueryable<SearchResultItem> query = context.GetQueryable<SearchResultItem>().Where(pred);
var hits = query.GetResults().Hits;
...
}
How can I perform exact phrase matching and is it possible with the Sitecore.ContentSearch.Linq API?
Answering my own question. The problem was with the parenthesis syntax. It should be
.Or(i => i.Name.Contains(term).Boost(1))
rather than
.Or(i => i.Name.Contains(term)).Boost(1)
The boosts were not being observed.
I think if you do the following it will solve this:
Split your search string on space
Create a predicate for each split with an equal boost value,
Create an additional predicate with the complete search string and
with higher boost value
combine all these predicates in one "OR" predicate.
Also I recommend you to check the following:
Sitecore Solr Search Score Value
http://sitecoreinfo.blogspot.com/2015/10/sitecore-solr-search-result-items.html
I'm kinda new to XPath and I've found that to get the max attribute number I can use the next statement: //Book[not(#id > //Book/#id) and it works quite well.
I just can't understand why does it return max id instead of min id, because it looks like I'm checking whether id of a node greater than any other nodes ids and then return a Book where it's not.
I'm probably stupid, but, please, someone, explain :)
You're not querying for maximum values, but for minimum values. Your query
//Book[not(#id > //Book/#id)
could be translated to natural language as "Find all books, which do not have an #id that is larger than any other book's #id". You probably want to use
//Book[not(#id < //Book/#id)
For arbitrary input you might have wanted to use <= instead, so it only returns a single maximum value (or none if it is shared). As #ids must be unique, this does not matter here.
Be aware that //Book[#id > //Book/#id] is not equal to the query above, although math would suggest so. XPath's comparison operators adhere to a kind of set-semantics: if any value on the left side is larger than any value on the right side, the predicate would be true; thus it would include all books but the one with minimum #id value.
Besides XPath 1.0 your function is correct, in XPath 2.0:
/Books/Book[id = max(../Book/id)]
The math:max function returns the maximum value of the nodes passed as the argument. The maximum value is defined as follows. The node set passed as an argument is sorted in descending order as it would be by xsl:sort with a data type of number. The maximum is the result of converting the string value of the first node in this sorted list to a number using the number function.
If the node set is empty, or if the result of converting the string values of any of the nodes to a number is NaN, then NaN is returned.
The math:max template returns a result tree fragment whose string value is the result of turning the number returned by the function into a string.
Using the count(preceding-sibling::*) XPath expression one can obtaining incrementing counters. However, can the same also be accomplished in a two-levels deep sequence?
example XML instance
<grandfather>
<father>
<child>a</child>
</father>
<father>
<child>b</child>
<child>c</child>
</father>
</grandfather>
code (with Saxon HE 9.4 jar on the CLASSPATH for XPath 2.0 features)
Trying to get an counter sequence of 1,2 and 3 for the three child nodes with different kinds of XPath expressions:
XPathExpression expr = xpath.compile("/grandfather/father/child");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
Node node = nodes.item(i);
System.out.printf("child's index is: %s %s %s, name is: %s\n"
,xpath.compile("count(preceding-sibling::*)").evaluate(node)
,xpath.compile("count(preceding-sibling::child)").evaluate(node)
,xpath.compile("//child/position()").evaluate(doc)
,xpath.compile(".").evaluate(node));
}
The above code prints:
child's index is: 0 0 1, name is: a
child's index is: 0 0 1, name is: b
child's index is: 1 1 1, name is: c
None of the three XPaths I tried managed to produce the correct sequence: 1,2,3. Clearly it can trivially be done using the i loop variable but I want to accomplish it with XPath if possible. Also I need to keep the basic framework of evaluating an XPath expression to get all the nodes to visit and then iterating on that set since that's the way the real application I work on is structured. Basically I visit each node and then need to evaluate a number of XPath expressions on it (node) or on the document (doc); one of these XPAth expressions is supposed to produce this incrementing sequence.
Use the preceding axis with a name test instead.
count(preceding::child)
Using XPath 2.0, there is a much better way to do this. Fetch all <child/> nodes and use the position() function to get the index:
//child/concat("child's index is: ", position(), ", name is: ", text())
You don't say efficiency is important, but I really hate to see this done with O(n^2) code! Jens' solution shows how to do that if you can use the result in the form of a sequence of (position, name) pairs. You could also return an alternating sequence of strings and numbers using //child/(string(.), position()): though you would then want to use the s9api API rather than JAXP, because JAXP can only really handle the data types that arise in XPath 1.0.
If you need to compute the index of each node as part of other processing, it might still be worth computing the index for every node in a single initial pass, and then looking it up in a table. But if you're doing that, the simplest way is surely to iterate over the result of //child and build a map from nodes to the sequence number in the iteration.
I'm trying to speed up a search function in a RoR app w/ Postgres DB. I won't explain how it works currently...just go with an /achieve approach!
I have x number of records (potentially a substantial number) which each have an associated array of Facebook ID numbers...potentially up to 5k. I need to search against this with an individual's list of friend IDs to ascertain if an intersect between the search array and any (and which) of the records' arrays exists.
I don't need to know the result of the intersection, just whether it's true or false.
Any bright ideas?!
Thanks!
Just using pure ruby since you don't mention your datastore:
friend_ids = user.friend_ids
results = records.select { |record| !(record.friend_ids & friend_ids).empty? }
results will contain all records that have at least 1 friend_id in common. This will not be very fast if you have to check a very large number of records.
& is the array intersection operator, which is implemented in C, you can see it here: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-26
A probably faster version of #ctcherry's answer, especially when user.friend_ids has high cardinality:
require 'set'
user_friend_ids = Set[ user.friend_ids ]
results = records.select { |record|
record.friend_ids.any? { |friend_id| user_friend_ids.include? friend_id }
}
Since this constructs the test set(hash) for user.freind_ids only once, it's probably also faster than the Array#memory_efficient_intersect linked by #Tass.
This may also be faster performed in the db, but without more info on the models, it's hard to compose an approach.