DMQL2 Query Syntax for PHRets v2 Seach() to include filter arguments? - filter

(It's been a while since I've been here.)
I've been using the first version of PHRets v1 for years, and understood it well enough to get by, but now I'm trying to understand the advantages of v2.6.2. I've got it all installed and the basics are working fine. My issues are pretty much with comprehending fine points of query syntax that goes into the rets=>Search() statement. (I'm much more familiar with SQL statements). Specifically, I'd like to have a query return a list of properties, EXCLUDING those which already have the status of "Sold".
Here's where I am stuck: If I start with this
`$results = $rets->Search('Property', 'A','*',['Select' => 'LIST_8,LIST_105,LIST_15,LIST_19,listing_office_shortid']);`
That works well enough. BUT I'd like to fit in a filter like:
"LIST_15 != Sold", or "NOT LIST_15=Sold"...something like that. I don't get how to fit/type that into a PHRets Search().
I like PHRets but it is so hard to find well-organized/complete documentation about specific things like this. Thanks in advance.

As in my comment above I've figured out that the filter goes in the third argument position ('*', as in the original question). The tricky thing was having to find a specific "sold" code for each class of properties and placing it in that position like so: '(LIST_15=~B4ZIT1Y75TZ)', (notice the =~ combination of characters that means "does not equal" in this context). I've found the code strings for each of the property types (not clear WHY they would need to be unique for each type of property: "Sold" is Sold for any type, after all) but the correct code for a single-family residential property (type 'A' ...at least for the MLS in which I have to search is:
$results = $rets->Search('Property', 'A','(LIST_15=~B4ZIT1Y75TZ)',['Select' => 'LIST_8,LIST_105,LIST_15,LIST_19,listing_office_shortid']);
(again, the code to go with LIST_15 will be different for the different types of properties.) I think there is a better answer that involves more naturalistic language, but this works and I guess I will have to be satisfied with it for now. I hope this is of some use to anyone else struggling with this stuff.

Related

Spring Data JPA fetching list always returns at least a single result

I've noticed a slight problem with how my API is working where I'm using Spring Data JPA.
My query looks something along the lines of:
#Query("SELECT p.id AS id, COUNT(l) AS likes FROM Post p LEFT JOIN Like l ON l.post = p WHERE p.location.id = ?1")
My actual query is bigger, this this contains everything necessary to explain what the issue is. This query will return a list, but assume the location does not exist, it should return null or an empty list, correct? Oh, how wrong you are, my sweet summer child!
This query will instead always return a list of at least one element, regardless of whether or not there are any posts linked to said location.
[{"id": null, "likes": 0}]
That is what the result looks like when serialized to JSON. I am not quite sure what to do about this little predicament, as I obviously don't want to return a list with faulty data, but needing to use processing to filter out duds also seems dumb and unnecessary.
Is there any way to prevent this that I've yet to find? If it is of any relevance, I am using projections currently for my responses.
What I've tried so far:
Adding a not null condition for fields. Does not work, ignored by COUNT.
Adding constraints to all fields #NotNull. Does not work, will still become null.
For what it's worth, I've tried different kinds of joins, though anything but LEFT JOIN doesn't make much sense.
I haven't been able to find any other case which resembles this either, although it most likely exists, but is drowned out by everything else. I'm not quite sure what can be done in this regard, so I'm curious if it's just a quirk with the framework, or if there is an actual solution.
It might be possible to solve through native queries, but I would prefer not to use them.
I'm no SQL expert but I believe that a left join will give you this result if the ID does not exist.
Have you run the query in your DB? Doesn't it give you one row in your result set for IDs that do not exist?
I believe this is intended to say there is a 0 match.
You might want to validate your query before running it. Meaning checking that the location exists first.
As the issue is inherently due to a COUNT and CASE keyword in my real query, resulting in there always being at least one row, and I can't find any method of doing this automatically, the solution I've used is the following:
List<Item> items = repository.customQuery(id);
if (0 < items.size() && null == items.get(0).getId()) {
items.remove(0);
}
The first condition is arbitrary as I know there is always at least one entry, but is done just as a safety measure. A try-catch block would do the trick as well. In the case where you use a primitive int instead of Integer, you'd need to initialize the value in the constructor to something which would normally never be present in the database, such as -1.
If anyone knows of a better method, I'd love to know about it.

Change the way an object is displayed in debugger/inspector variable-value table

I would like to know if there is a message I can override in Pharo so that my custom classes display more descriptive information in the inspector/debuger much like simple variable types do, like Integers or Strings. For instance:
Instead of that, I would like it to show a more custom and informative description consisting of its internal variales so as to have a tighter/tidier view of the variables instead of having to click on it and open another chart (therefore losing sight of the information on the previous chart). I know you can increase the amount of charts shown below, but that is not the point of the question. I would like to achieve something like this:
I have browsed the pharo forums and found nothing, I have also tried overriding over 30 methods hoping that one of them changed the output. Only the class message seemed to change the output, but I could only return an instance of Metaclass and besides messing with this message would break a lot of stuff. Finally I tried to reverse engineer the debugger and then the inspector to see at which point is the table constructed and what values are used or which messages are sent to build said values, but it was just too much for me, the callstack kept growing and I couldn't even scratch the surface.
Luckily, doing this in any Smalltalk is very easy. Types inherited from Object are expected to answer to the message printString, and ultimately printOn: aStream. Those messages are expected to give a description of the object. So, you should just override printOn: in your class (printString uses printOn:) and all the browsers and inspectors will automatically use it. There other possibilities in Pharo, if you want to provide more complex information in different tabs, but I think printOn: will suffice for you.
An example would be:
MyPoint>>printOn: aStream
aStream nextPut: ${.
x printOn: aStream.
aStream nextPutAll: ', '
y printOn: aStream.
aStream nextPut: $}
In Smalltalk, every time you observe something you don't like or understand, you ask the question: Which message is doing this?
In your case, the question would be: Which message creates the string a MyPoint that I see everywhere?
Next, to answer your question you need to find a good place for inserting a halt and then debug from there until you find the culprit. To do this just find the simplest expression that would reproduce the issue and debug it. In your case the right-click command in the Playground will do. So,
Write and select (MyPoint on: 14 and: -5) halt in a Playground.
Right-click and issue the Print it command (I'm assuming you already checked that this command produces the string 'a MyPoint').
Debug
Go over the evaluation of #DoIt, which answers the result
Continue this way alternating between Into and Over to make sure you follow the result to where it's being taken
Eventually you will reach the implementation of Object >> #printString. Bingo!
Now you can open a System Browser and take a look at this method, study how it's been implemented in different classes, etc. Your investigation should show you that the most basic message for printing is #printOn:. You may also want to take a look at other implementors so to better understand what people usually do. (Bear in mind that writing good #printOn:s is a minimalist art)
Overriding printOn: will work for simple cases where you want to just change description.
Pharo allows a lot more than that!
Due the extensible (moldable) nature of our inspector, you do not need to override a method to get your own visualisation of the object.
For example, look this array visualisation:
This is obtained adding this method to Collection:
gtInspectorItemsIn: composite
<gtInspectorPresentationOrder: 0>
^ composite fastList
title: 'Items';
display: [ self asOrderedCollection ];
beMultiple;
format: [ :each | GTObjectPrinter asTruncatedTextFrom: each ];
send: [ :result |
result
ifNil: [ nil ]
ifNotNil: [ result size = 1
ifTrue: [ result anyOne ]
ifFalse: [ self species withAll: result ]
]
]
if you browse for senders of gtInspectorPresentationOrder: you will see there are already a lot of special visualisations in the image.
You can take those as an example on how to create your own, adapted exactly to what you need :)

Solr query conundrum

I've recently swapped from using Lucene for Sitecore to Solr.
For the most part it has been smooth, but the way I was writing some queries (using Sitecore.ContentSearch.Linq) abstraction now don't seem to be compatible.
Specifically, I have a situation where I've got "global" content and "regional" content, like so:
Home (000)
X
Y
Z
Regions (ID: 111)
Region 1 (ID: 221)
A
B
Region 2 (ID: 222)
D
My code worked on Lucene, but now doesn't on Solr. It should find all "global" and a single region's content, excluding all other region's content. So as an example, if the user's current region was Region 1, I'd want the query to return content X, Y, Z, A, B.
Sitecore's Item Crawler has a field for each item in the index called "_path" which is a multivalued string field of IDs, so as an example, Region 1's _path field value would be [000, 111, 221 ].
When I write this using the Linq abstraction it comes out as below which doesn't return results.
-_path:(111) OR _path:(221)
But _path:(111) does return result. Mind blown.
When I use the Solr interface and wrap each side of the OR in extra brackets like below (which I'd consider redundant) it works! Mind blown v2.
(-_path:(111)) OR (_path:(221))
Firstly, what's the difference between those queries?
Secondly, my real problem is I can't add these extra brackets as I'm working in an abstraction Linq so the brackets will be "optimized" out.
Any advice would be awesome! Cheers.
The problem here is, lucene's negative queries don't work like you think they do. They only remove results from what has been found. -_path:111 doesn't find all documents which aren't in 111, it doesn't find anything at all. It only removes results. So you are finding all results with path "221", then removing any that also have path "111", which from your heirarchy, I assume is all of them. See my answer here for a bit more on that topic.
The OR makes it seem like it ought to work, but really -_path:(111) OR _path:(221) is the same as -_path:(111) _path:(221). The moral here is: Don't use Lucene's AND/OR/NOT syntax, if you can help it. Use +/-. +/- syntax actually expresses how the query operates, AND/OR/NOT doesn't. It attempts to shoehorn it into a different, SQL-like retrieval model and leads to some unexpected behavior like this.
So, what about: (-_path:(111)) OR (_path:(221))
Well, first, does it actually work? Or does it just get some results?
If it just gets some results, but just seems to get the same results as _path:221: The reason is -_path:111 gets no results, so your query is, in practice, something like: (nothing) OR (_path:221), which is equivalent to _path:221
If it really does get the results you expect (I'm guessing it probably does): Something is translating your query into something like: (*:* -_path:111) (_path:221). Solr does have some logic along these lines, though I'm not quite sure in this case. Essentially, it puts a match-all in front of any lonely negative queries it finds, allowing them to do what you were expecting. If the implicit *:* makes you nervous about performance, well, it should. But lucene is an inverted index, it does well with finding matches on a term quickly. Getting everything that doesn't match goes against the grain of that retrieval model, and will pretty much have to do a full scan of the index.

Find HTML Tags in Properties

My current issue is to find HTML-Tags inside of property values. I thought it would be easy to search with a query like /jcr:root/content/xgermany//*[jcr:contains(., '<strong>')] order by #jcr:score
It looks like there is a problem with the chars < and > because this query finds everything which has strong in it's property. It finds <strong>Some Text</strong> but also This is a strong man.
Also the Query Builder API didn't helped me.
Is there a possibility to solve it with a XPath or SQL Query or do I have to iterate through the whole content?
I don't fully understand why it finds This is a strong man as a result for '<strong>', but it sounds like the unexpected behavior comes from the "simple search-engine syntax" for the second argument to jcr:contains(). Apparently the < > are just being ignored as "meaningless" punctuation.
You could try quoting the search term:
/jcr:root/content/xgermany//*[jcr:contains(., '"<strong>"')]
though you may have to tweak that if your whole XPath expression is enclosed in double quotes.
Of course this will not be very robust even if it works, since you're trying to find HTML elements by searching for fixed strings, instead of actually parsing the HTML.
If you have an specific jcr:primaryType and the targeted properties you can do something like this
select * from nt:unstructured where text like '%<strong>%'
I tested it , but you need to know the properties you are intererested in.
This is jcr-sql syntax
Start using predicates like a champ this way all of this will make sense to you!
HTML Encode <strong>
HTML Decimal <strong>
Query builder is your friend:
Predicates: (like a CHAMP!)
path=/content/geometrixx
type=nt:unstructured
property=text
property.operation=like
property.value=%<strong>%
Have go here:
http://localhost:4502/libs/cq/search/content/querydebug.html?charset=UTF-8&query=path%3D%2Fcontent%2Fgeometrixx%0D%0Atype%3Dnt%3Aunstructured%0D%0Aproperty%3Dtext%0D%0Aproperty.operation%3Dlike%0D%0Aproperty.value%3D%25%3Cstrong%3E%25
Predicates: (like a CHAMP!)
path=/content/geometrixx
type=nt:unstructured
property=text
property.operation=like
property.value=%<strong>%
Have a go here:
http://localhost:4502/libs/cq/search/content/querydebug.html?charset=UTF-8&query=path%3D%2Fcontent%2Fgeometrixx%0D%0Atype%3Dnt%3Aunstructured%0D%0Aproperty%3Dtext%0D%0Aproperty.operation%3Dlike%0D%0Aproperty.value%3D%25%26lt%3Bstrong%26gt%3B%25
XPath:
/jcr:root/content/geometrixx//element(*, nt:unstructured)
[
jcr:like(#text, '%<strong>%')
]
SQL2 (already covered... NASTY YUK..)
SELECT * FROM [nt:unstructured] AS s WHERE ISDESCENDANTNODE([/content/geometrixx]) and text like '%<strong>%'
Although I'm sure it's entirely possible with a string of predicates, it's possibly heading down the wrong route. Ideally it would be better to parse the HTML when it is stored or published.
The required information would be stored on simple properties on the node in question. The query will then be a lot simpler with just a property = value query, than lots of overly complex query syntax.
It will probably be faster too.
So if you read in your HTML with something like HTMLClient and then parse it with a OSGI service, that can accurately save these properties for you. Every time the HTML is changed the process would update these properties as necessary. Just some thoughts if your SQL is getting too much.

LINQ - OR two SqlMethods.Like clauses

I need to OR two SqlMethods.Like statements in LINQ, and I'm not sure how to accomplish it (or if it's the right way to go about it).
I've got vendor ID and vendor name fields, but I've only got a generic vendor search that allows a user to search for a vendor based on their name or ID. I also allow wildcards in the search, so I need to find vendors whose ID or name is like the user's input.
I want to do something like below, but obviously it's not correct. (EDIT: It does work as written.)
results = results.Where(p => SqlMethods.Like(p.VendorId, inputVendor.Replace("*", "%") ||
SqlMethods.Like(p.VendorName, inputVendor.Replace("*", "%"));
Background: I add where statements depending on the search parameters entered by the user, hence the results = results.Where part.
Any help would be appreciated!
It's not clear to me why this is "obviously" not correct. Presumably it's not working, otherwise you wouldn't have posted, but it's not obvious how it's not working.
I would suggest performing the replacement before the query, like this:
string vendorPattern = inputVendor.Replace("*", "%");
But then I'd expect this to work:
results = results.Where(p => SqlMethods.Like(p.VendorId, vendorPattern) ||
SqlMethods.Like(p.VendorName, vendorPattern));
Of course you're limited to where wildcards can appear in a SQL LIKE query, but that's a separate problem. (I'm not sure of the behaviour offhand if it's not at the start or end.)
If that doesn't help, please update the question with what happens when you try this.

Resources